From 6c1fe6ea3e4e3915fc4164c43230210f9a0ac24f Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Tue, 23 Jun 2015 11:54:19 +0100 Subject: Implement Clone. Fixes issue #527. --- .../protobuf/compiler/csharp/csharp_field_base.h | 1 + .../protobuf/compiler/csharp/csharp_message.cc | 59 +++++++++++++++++++--- .../protobuf/compiler/csharp/csharp_message.h | 1 + .../compiler/csharp/csharp_message_field.cc | 10 ++++ .../compiler/csharp/csharp_message_field.h | 2 + .../compiler/csharp/csharp_primitive_field.cc | 10 ++++ .../compiler/csharp/csharp_primitive_field.h | 2 + .../compiler/csharp/csharp_repeated_enum_field.cc | 5 ++ .../compiler/csharp/csharp_repeated_enum_field.h | 1 + .../csharp/csharp_repeated_message_field.cc | 5 ++ .../csharp/csharp_repeated_message_field.h | 1 + .../csharp/csharp_repeated_primitive_field.cc | 5 ++ .../csharp/csharp_repeated_primitive_field.h | 1 + 13 files changed, 95 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h index 1b044a49..91ae3ba1 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -47,6 +47,7 @@ class FieldGeneratorBase : public SourceGeneratorBase { FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal); ~FieldGeneratorBase(); + virtual void GenerateCloningCode(io::Printer* printer) = 0; virtual void GenerateMembers(io::Printer* printer) = 0; virtual void GenerateMergingCode(io::Printer* printer) = 0; virtual void GenerateParsingCode(io::Printer* printer) = 0; diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index aca68fb7..32d0a82d 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -179,7 +179,7 @@ void MessageGenerator::Generate(io::Printer* printer) { WriteGeneratedCodeAttributes(printer); printer->Print( vars, - "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$>, global::System.IEquatable<$class_name$> {\n"); + "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$>, global::System.IEquatable<$class_name$>, pb::IDeepCloneable<$class_name$> {\n"); printer->Indent(); // All static fields and properties @@ -213,16 +213,12 @@ void MessageGenerator::Generate(io::Printer* printer) { "}\n" "\n"); - // Constructors + // Parameterless constructor printer->Print( vars, - "public $class_name$() { }\n"); // Public parameterless ctor. + "public $class_name$() { }\n\n"); - printer->Print( - vars, - "public $class_name$($class_name$ other) {\n" - " MergeFrom(other);\n" - "}\n"); // Merge ctor. + GenerateCloningCode(printer); // Fields/properties for (int i = 0; i < descriptor_->field_count(); i++) { @@ -303,6 +299,53 @@ void MessageGenerator::Generate(io::Printer* printer) { } +void MessageGenerator::GenerateCloningCode(io::Printer* printer) { + map vars; + vars["class_name"] = class_name(); + printer->Print( + vars, + "public $class_name$($class_name$ other) {\n"); + printer->Indent(); + // Clone non-oneof fields first + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + scoped_ptr generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->GenerateCloningCode(printer); + } + } + // Clone just the right field for each oneof + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); + vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); + printer->Print(vars, "switch (other.$property_name$Case) {\n"); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + scoped_ptr generator(CreateFieldGeneratorInternal(field)); + vars["field_property_name"] = GetPropertyName(field); + printer->Print( + vars, + "case $property_name$OneofCase.$field_property_name$:\n"); + printer->Indent(); + generator->GenerateCloningCode(printer); + printer->Print("break;\n"); + printer->Outdent(); + } + printer->Outdent(); + printer->Print("}\n\n"); + } + + printer->Outdent(); + printer->Print("}\n\n"); + + printer->Print( + vars, + "public $class_name$ Clone() {\n" + " return new $class_name$(this);\n" + "}\n\n"); +} + void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) { map vars; vars["class_name"] = class_name(); diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h index eb90ce67..c3a37a0e 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.h +++ b/src/google/protobuf/compiler/csharp/csharp_message.h @@ -50,6 +50,7 @@ class MessageGenerator : public SourceGeneratorBase { MessageGenerator(const Descriptor* descriptor); ~MessageGenerator(); + void GenerateCloningCode(io::Printer* printer); void GenerateFrameworkMethods(io::Printer* printer); void GenerateStaticVariables(io::Printer* printer); void GenerateStaticVariableInitializers(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc index bd67aa0f..82deef54 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -125,6 +125,11 @@ void MessageFieldGenerator::WriteToString(io::Printer* printer) { "PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n"); } +void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$property_name$ = other.$has_property_check$ ? other.$property_name$.Clone() : null;\n"); +} + MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal) : MessageFieldGenerator(descriptor, fieldOrdinal) { @@ -166,6 +171,11 @@ void MessageOneofFieldGenerator::WriteToString(io::Printer* printer) { "PrintField(\"$descriptor_name$\", $has_property_check$, $oneof_name$_, writer);\n"); } +void MessageOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$property_name$ = other.$property_name$.Clone();\n"); +} + } // namespace csharp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h index 02053b4f..f15e8e7e 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h @@ -46,6 +46,7 @@ class MessageFieldGenerator : public FieldGeneratorBase { MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); ~MessageFieldGenerator(); + virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer); virtual void GenerateMergingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer); @@ -65,6 +66,7 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); ~MessageOneofFieldGenerator(); + virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer); virtual void WriteToString(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc index 5820eb37..c426c37a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -146,6 +146,11 @@ void PrimitiveFieldGenerator::WriteToString(io::Printer* printer) { "PrintField(\"$descriptor_name$\", $has_property_check$, $property_name$, writer);\n"); } +void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_;\n"); +} + PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( const FieldDescriptor* descriptor, int fieldOrdinal) : PrimitiveFieldGenerator(descriptor, fieldOrdinal) { @@ -189,6 +194,11 @@ void PrimitiveOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) { "$property_name$ = input.Read$capitalized_type_name$();\n"); } +void PrimitiveOneofFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$property_name$ = other.$property_name$;\n"); +} + } // namespace csharp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h index d6672b6c..bac33214 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h @@ -46,6 +46,7 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase { PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); ~PrimitiveFieldGenerator(); + virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer); virtual void GenerateMergingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer); @@ -68,6 +69,7 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); ~PrimitiveOneofFieldGenerator(); + virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer); virtual void WriteToString(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc index 29c931e3..ce526b37 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc @@ -142,6 +142,11 @@ void RepeatedEnumFieldGenerator::WriteToString(io::Printer* printer) { "PrintField(\"$descriptor_name$\", $name$_, writer);\n"); } +void RepeatedEnumFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_.Clone();\n"); +} + } // namespace csharp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h index 92f265c5..c7846a61 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h @@ -48,6 +48,7 @@ class RepeatedEnumFieldGenerator : public FieldGeneratorBase { RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); ~RepeatedEnumFieldGenerator(); + virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer); virtual void GenerateMergingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc index 3ab0b190..edfb98b4 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc @@ -118,6 +118,11 @@ void RepeatedMessageFieldGenerator::WriteToString(io::Printer* printer) { "PrintField(\"$field_name$\", $name$_, writer);\n"); } +void RepeatedMessageFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_.Clone();\n"); +} + } // namespace csharp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h index b8582800..38006731 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h @@ -46,6 +46,7 @@ class RepeatedMessageFieldGenerator : public FieldGeneratorBase { RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); ~RepeatedMessageFieldGenerator(); + virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer); virtual void GenerateMergingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc index cc787d50..49a29c55 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc @@ -148,6 +148,11 @@ void RepeatedPrimitiveFieldGenerator::WriteToString(io::Printer* printer) { "PrintField(\"$descriptor_name$\", $name$_, writer);\n"); } +void RepeatedPrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_ = other.$name$_.Clone();\n"); +} + } // namespace csharp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h index 29d437d7..7f8f17a8 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h @@ -46,6 +46,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase { RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); ~RepeatedPrimitiveFieldGenerator(); + virtual void GenerateCloningCode(io::Printer* printer); virtual void GenerateMembers(io::Printer* printer); virtual void GenerateMergingCode(io::Printer* printer); virtual void GenerateParsingCode(io::Printer* printer); -- cgit v1.2.3