From f7b417ddfe63cb4d39775e5fd4560894cc547d65 Mon Sep 17 00:00:00 2001 From: Jie Luo Date: Fri, 29 May 2015 12:48:25 -0700 Subject: Add oneof support for C# --- .../protobuf/compiler/csharp/csharp_enum_field.cc | 117 ++++++++++++++++---- .../protobuf/compiler/csharp/csharp_enum_field.h | 18 ++++ .../protobuf/compiler/csharp/csharp_field_base.cc | 8 ++ .../protobuf/compiler/csharp/csharp_field_base.h | 2 + .../protobuf/compiler/csharp/csharp_helpers.cc | 18 +++- .../protobuf/compiler/csharp/csharp_message.cc | 95 +++++++++++++++-- .../compiler/csharp/csharp_message_field.cc | 118 ++++++++++++++++++++- .../compiler/csharp/csharp_message_field.h | 18 ++++ .../compiler/csharp/csharp_primitive_field.cc | 104 ++++++++++++++---- .../compiler/csharp/csharp_primitive_field.h | 18 ++++ 10 files changed, 463 insertions(+), 53 deletions(-) (limited to 'src') diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc index 34d1c5c6..a2d8a98b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc @@ -49,6 +49,11 @@ namespace csharp { EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal) : FieldGeneratorBase(descriptor, fieldOrdinal) { + if (SupportFieldPresence(descriptor_->file())) { + has_property_check = "has" + property_name(); + } else { + has_property_check = property_name() + " != " + default_value(); + } } EnumFieldGenerator::~EnumFieldGenerator() { @@ -122,8 +127,7 @@ void EnumFieldGenerator::GenerateBuildingCode(Writer* writer) { void EnumFieldGenerator::GenerateParsingCode(Writer* writer) { writer->WriteLine("object unknown;"); - writer->WriteLine("if(input.ReadEnum(ref result.$0$_, out unknown)) {", - name()); + writer->WriteLine("if(input.ReadEnum(ref result.$0$_, out unknown)) {", name()); if (SupportFieldPresence(descriptor_->file())) { writer->WriteLine(" result.has$0$ = true;", property_name()); } @@ -141,11 +145,7 @@ void EnumFieldGenerator::GenerateParsingCode(Writer* writer) { } void EnumFieldGenerator::GenerateSerializationCode(Writer* writer) { - if (SupportFieldPresence(descriptor_->file())) { - writer->WriteLine("if (has$0$) {", property_name()); - } else { - writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); - } + writer->WriteLine("if ($0$) {", has_property_check); writer->WriteLine( " output.WriteEnum($0$, field_names[$2$], (int) $1$, $1$);", number(), property_name(), field_ordinal()); @@ -153,11 +153,7 @@ void EnumFieldGenerator::GenerateSerializationCode(Writer* writer) { } void EnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { - if (SupportFieldPresence(descriptor_->file())) { - writer->WriteLine("if (has$0$) {", property_name()); - } else { - writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); - } + writer->WriteLine("if ($0$) {", has_property_check); writer->WriteLine( " size += pb::CodedOutputStream.ComputeEnumSize($0$, (int) $1$);", number(), property_name()); @@ -165,11 +161,7 @@ void EnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { } void EnumFieldGenerator::WriteHash(Writer* writer) { - if (SupportFieldPresence(descriptor_->file())) { - writer->WriteLine("if (has$0$) {", property_name()); - } else { - writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); - } + writer->WriteLine("if ($0$) {", has_property_check); writer->WriteLine(" hash ^= $0$_.GetHashCode();", name()); writer->WriteLine("}"); } @@ -184,13 +176,94 @@ void EnumFieldGenerator::WriteEquals(Writer* writer) { } } void EnumFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$, $2$_, writer);", + descriptor_->name(), has_property_check, name()); +} + +EnumOneofFieldGenerator::EnumOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal) + : EnumFieldGenerator(descriptor, fieldOrdinal) { + has_property_check = oneof_name() + "Case_ == " + oneof_property_name() + + "OneofCase." + property_name(); +} + +EnumOneofFieldGenerator::~EnumOneofFieldGenerator() { +} + +void EnumOneofFieldGenerator::GenerateMembers(Writer* writer) { + AddDeprecatedFlag(writer); if (SupportFieldPresence(descriptor_->file())) { - writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);", - descriptor_->name(), property_name(), name()); - } else { - writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", - descriptor_->name(), name()); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return $0$; }", has_property_check); + writer->WriteLine("}"); + } + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$ ? ($1$) $2$_ : $3$; }", + has_property_check, type_name(), oneof_name(), default_value()); + writer->WriteLine("}"); +} + +void EnumOneofFieldGenerator::GenerateBuilderMembers(Writer* writer) { + AddDeprecatedFlag(writer); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.$0$; }", has_property_check); + writer->WriteLine("}"); } + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$ ? ($1$) result.$2$_ : $3$; }", + has_property_check, type_name(), oneof_name(), default_value()); + writer->WriteLine(" set { Set$0$(value); }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public Builder Set$0$($1$ value) {", property_name(), + type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_ = value;", oneof_name()); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.$2$;", + oneof_name(), oneof_property_name(), property_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" if (result.$0$) {", has_property_check); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.None;", + oneof_name(), oneof_property_name()); + writer->WriteLine(" }"); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void EnumOneofFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if (!$0$.Equals(other.$0$)) return false;", property_name()); +} +void EnumOneofFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$, $2$_, writer);", + descriptor_->name(), has_property_check, oneof_name()); +} + +void EnumOneofFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("object unknown;"); + writer->WriteLine("$0$ enumValue = $1$;", type_name(), default_value()); + writer->WriteLine("if(input.ReadEnum(ref enumValue, out unknown)) {", + name()); + writer->WriteLine(" result.$0$_ = enumValue;", oneof_name()); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.$2$;", + oneof_name(), oneof_property_name(), property_name()); + writer->WriteLine("} else if(unknown is int) {"); + if (!use_lite_runtime()) { + writer->WriteLine(" if (unknownFields == null) {"); // First unknown field - create builder now + writer->WriteLine( + " unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);"); + writer->WriteLine(" }"); + writer->WriteLine( + " unknownFields.MergeVarintField($0$, (ulong)(int)unknown);", + number()); + } + writer->WriteLine("}"); } } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_enum_field.h index b21fa9dc..565287b2 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h @@ -60,10 +60,28 @@ class EnumFieldGenerator : public FieldGeneratorBase { virtual void WriteEquals(Writer* writer); virtual void WriteToString(Writer* writer); + protected: + string has_property_check; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); }; +class EnumOneofFieldGenerator : public EnumFieldGenerator { + public: + EnumOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~EnumOneofFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator); +}; + } // namespace csharp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc index 145b6743..dfc803e6 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -81,6 +81,14 @@ void FieldGeneratorBase::AddPublicMemberAttributes(Writer* writer) { AddDeprecatedFlag(writer); } +std::string FieldGeneratorBase::oneof_property_name() { + return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), true); +} + +std::string FieldGeneratorBase::oneof_name() { + return UnderscoresToCamelCase(descriptor_->containing_oneof()->name(), false); +} + std::string FieldGeneratorBase::property_name() { return GetPropertyName(descriptor_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h index 311f7a6e..312da12b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -71,6 +71,8 @@ class FieldGeneratorBase : public SourceGeneratorBase { void AddPublicMemberAttributes(Writer* writer); + std::string oneof_property_name(); + std::string oneof_name(); std::string property_name(); std::string name(); std::string type_name(); diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc index 4580b7be..76e2c850 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -346,19 +346,31 @@ FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, if (descriptor->is_repeated()) { return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal); } else { - return new MessageFieldGenerator(descriptor, fieldOrdinal); + if (descriptor->containing_oneof()) { + return new MessageOneofFieldGenerator(descriptor, fieldOrdinal); + } else { + return new MessageFieldGenerator(descriptor, fieldOrdinal); + } } case FieldDescriptor::TYPE_ENUM: if (descriptor->is_repeated()) { return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal); } else { - return new EnumFieldGenerator(descriptor, fieldOrdinal); + if (descriptor->containing_oneof()) { + return new EnumOneofFieldGenerator(descriptor, fieldOrdinal); + } else { + return new EnumFieldGenerator(descriptor, fieldOrdinal); + } } default: if (descriptor->is_repeated()) { return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal); } else { - return new PrimitiveFieldGenerator(descriptor, fieldOrdinal); + if (descriptor->containing_oneof()) { + return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal); + } else { + return new PrimitiveFieldGenerator(descriptor, fieldOrdinal); + } } } } diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index 96f7c17c..22681235 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -156,6 +156,10 @@ void MessageGenerator::GenerateStaticVariableInitializers(Writer* writer) { for (int i = 0; i < descriptor_->field_count(); i++) { writer->Write("\"$0$\", ", GetPropertyName(descriptor_->field(i))); } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + writer->Write("\"$0$\", ", + UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true)); + } writer->WriteLine("});"); } @@ -260,6 +264,31 @@ void MessageGenerator::Generate(Writer* writer) { writer->WriteLine(); } + // oneof + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + string name = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); + string property_name = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); + writer->WriteLine("private object $0$_;", name); + writer->WriteLine("public enum $0$OneofCase {", property_name); + writer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + writer->WriteLine("$0$ = $1$,", + GetPropertyName(field), + SimpleItoa(field->number())); + } + writer->WriteLine("None = 0,"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("private $0$OneofCase $1$Case_ = $0$OneofCase.None;", + property_name, name); + writer->WriteLine("public $0$OneofCase $0$Case {", property_name); + writer->WriteLine(" get { return $0$Case_; }", name); + writer->WriteLine("}"); + writer->WriteLine(); + } + + // Fields for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* fieldDescriptor = descriptor_->field(i); @@ -310,9 +339,19 @@ void MessageGenerator::GenerateLiteRuntimeMethods(Writer* writer) { writer->Indent(); writer->WriteLine("int hash = GetType().GetHashCode();"); for (int i = 0; i < descriptor_->field_count(); i++) { - scoped_ptr generator( - CreateFieldGeneratorInternal(descriptor_->field(i))); - generator->WriteHash(writer); + const FieldDescriptor* field = descriptor_->field(i); + if (field->containing_oneof() == NULL) { + scoped_ptr generator( + CreateFieldGeneratorInternal(field)); + generator->WriteHash(writer); + } + } + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + string name = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); + string property_name = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); + writer->WriteLine("if ($0$Case_ != $1$OneofCase.None) {", name, property_name); + writer->WriteLine(" hash ^= $0$_.GetHashCode();", name); + writer->WriteLine("}"); } if (callbase) { writer->WriteLine("hash ^= base.GetHashCode();"); @@ -577,6 +616,23 @@ void MessageGenerator::GenerateBuilder(Writer* writer) { // No field comment :( generator->GenerateBuilderMembers(writer); } + + // oneof + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + writer->WriteLine(); + string name = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); + string property_name = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); + writer->WriteLine("public $0$OneofCase $0$Case {", property_name); + writer->WriteLine(" get { return result.$0$Case_; }", name); + writer->WriteLine("}"); + writer->WriteLine("public Builder Clear$0$() {", property_name); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_ = null;", name); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.None;", name, property_name); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + } + writer->Outdent(); writer->WriteLine("}"); } @@ -675,10 +731,37 @@ void MessageGenerator::GenerateCommonBuilderMethods(Writer* writer) { full_class_name()); writer->WriteLine("PrepareBuilder();"); for (int i = 0; i < descriptor_->field_count(); i++) { - scoped_ptr generator( - CreateFieldGeneratorInternal(descriptor_->field(i))); - generator->GenerateMergingCode(writer); + if (!descriptor_->field(i)->containing_oneof()) { + scoped_ptr generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->GenerateMergingCode(writer); + } + } + + // Merge oneof fields + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + string name = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); + string property_name = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); + writer->WriteLine("switch (other.$0$Case) {", property_name); + writer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + writer->WriteLine("case $0$OneofCase.$1$: {", + property_name, GetPropertyName(field)); + if (field->type() == FieldDescriptor::TYPE_GROUP || + field->type() == FieldDescriptor::TYPE_MESSAGE) { + writer->WriteLine(" Merge$0$(other.$0$);", GetPropertyName(field)); + } else { + writer->WriteLine(" Set$0$(other.$0$);", GetPropertyName(field)); + } + writer->WriteLine(" break;"); + writer->WriteLine("}"); + } + writer->WriteLine("case $0$OneofCase.None: { break; }", property_name); + writer->Outdent(); + writer->WriteLine("}"); } + // if message type has extensions if (descriptor_->extension_range_count() > 0) { writer->WriteLine(" this.MergeExtensionFields(other);"); diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc index 10464c4b..b533d735 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -50,6 +50,7 @@ namespace csharp { MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal) : FieldGeneratorBase(descriptor, fieldOrdinal) { + has_property_check = "has" + property_name(); } MessageFieldGenerator::~MessageFieldGenerator() { @@ -149,7 +150,7 @@ void MessageFieldGenerator::GenerateParsingCode(Writer* writer) { } void MessageFieldGenerator::GenerateSerializationCode(Writer* writer) { - writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine("if ($0$) {", has_property_check); writer->WriteLine(" output.Write$0$($1$, field_names[$3$], $2$);", message_or_group(), number(), property_name(), field_ordinal()); @@ -157,7 +158,7 @@ void MessageFieldGenerator::GenerateSerializationCode(Writer* writer) { } void MessageFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { - writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine("if ($0$) {", has_property_check); writer->WriteLine(" size += pb::CodedOutputStream.Compute$0$Size($1$, $2$);", message_or_group(), number(), property_name()); writer->WriteLine("}"); @@ -177,6 +178,119 @@ void MessageFieldGenerator::WriteToString(Writer* writer) { property_name(), name(), GetFieldName(descriptor_)); } +MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal) + : MessageFieldGenerator(descriptor, fieldOrdinal) { + has_property_check = oneof_name() + "Case_ == " + oneof_property_name() + + "OneofCase." + property_name(); +} + +MessageOneofFieldGenerator::~MessageOneofFieldGenerator() { + +} + +void MessageOneofFieldGenerator::GenerateMembers(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return $0$; }", has_property_check); + writer->WriteLine("}"); + } + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$ ? ($1$) $2$_ : $3$; }", + has_property_check, type_name(), oneof_name(), default_value()); + writer->WriteLine("}"); +} + +void MessageOneofFieldGenerator::GenerateBuilderMembers(Writer* writer) { + if (SupportFieldPresence(descriptor_->file())) { + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.$0$; }", has_property_check); + writer->WriteLine("}"); + } + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$ ? ($1$) result.$2$_ : $3$; }", + has_property_check, type_name(), oneof_name(), default_value()); + writer->WriteLine(" set { Set$0$(value); }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Set$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.$2$;", + oneof_name(), oneof_property_name(), property_name()); + writer->WriteLine(" result.$0$_ = value;", oneof_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Set$0$($1$.Builder builderForValue) {", + property_name(), type_name()); + AddNullCheck(writer, "builderForValue"); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.$2$;", + oneof_name(), oneof_property_name(), property_name()); + writer->WriteLine(" result.$0$_ = builderForValue.Build();", oneof_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Merge$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" if (result.$0$ &&", has_property_check); + writer->WriteLine(" result.$0$ != $1$) {", property_name(), default_value()); + writer->WriteLine( + " result.$0$_ = $1$.CreateBuilder(result.$2$).MergeFrom(value).BuildPartial();", + oneof_name(), type_name(), property_name()); + writer->WriteLine(" } else {"); + writer->WriteLine(" result.$0$_ = value;", oneof_name()); + writer->WriteLine(" }"); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.$2$;", + oneof_name(), oneof_property_name(), property_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" if (result.$0$) {", has_property_check); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.None;", + oneof_name(), oneof_property_name()); + writer->WriteLine(" result.$0$_ = null;", oneof_name()); + writer->WriteLine(" }"); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void MessageOneofFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("$0$.Builder subBuilder = $0$.CreateBuilder();", + type_name()); + writer->WriteLine("if (result.$0$) {", has_property_check); + writer->WriteLine(" subBuilder.MergeFrom($0$);", property_name()); + writer->WriteLine("}"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + writer->WriteLine("input.ReadGroup($0$, subBuilder, extensionRegistry);", + number()); + } else { + writer->WriteLine("input.ReadMessage(subBuilder, extensionRegistry);"); + } + writer->WriteLine("result.$0$_ = subBuilder.BuildPartial();", oneof_name()); + writer->WriteLine("result.$0$Case_ = $1$OneofCase.$2$;", + oneof_name(), oneof_property_name(), property_name()); +} + +void MessageOneofFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if (!$0$.Equals(other.$0$)) return false;", property_name()); +} +void MessageOneofFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$, $2$_, writer);", + descriptor_->name(), has_property_check, oneof_name()); +} + } // 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 48bf8be5..d455ade5 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h @@ -60,10 +60,28 @@ class MessageFieldGenerator : public FieldGeneratorBase { virtual void WriteEquals(Writer* writer); virtual void WriteToString(Writer* writer); + protected: + string has_property_check; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); }; +class MessageOneofFieldGenerator : public MessageFieldGenerator { + public: + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~MessageOneofFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); +}; + } // namespace csharp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc index a193afda..a54edfe3 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -50,6 +50,11 @@ namespace csharp { PrimitiveFieldGenerator::PrimitiveFieldGenerator( const FieldDescriptor* descriptor, int fieldOrdinal) : FieldGeneratorBase(descriptor, fieldOrdinal) { + if (SupportFieldPresence(descriptor_->file())) { + has_property_check = "has" + property_name(); + } else { + has_property_check = property_name() + " != " + default_value(); + } } PrimitiveFieldGenerator::~PrimitiveFieldGenerator() { @@ -133,11 +138,7 @@ void PrimitiveFieldGenerator::GenerateParsingCode(Writer* writer) { } void PrimitiveFieldGenerator::GenerateSerializationCode(Writer* writer) { - if (SupportFieldPresence(descriptor_->file())) { - writer->WriteLine("if (has$0$) {", property_name()); - } else { - writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); - } + writer->WriteLine("if ($0$) {", has_property_check); writer->WriteLine(" output.Write$0$($1$, field_names[$3$], $2$);", capitalized_type_name(), number(), property_name(), field_ordinal()); @@ -145,22 +146,14 @@ void PrimitiveFieldGenerator::GenerateSerializationCode(Writer* writer) { } void PrimitiveFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { - if (SupportFieldPresence(descriptor_->file())) { - writer->WriteLine("if (has$0$) {", property_name()); - } else { - writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); - } + writer->WriteLine("if ($0$) {", has_property_check); writer->WriteLine(" size += pb::CodedOutputStream.Compute$0$Size($1$, $2$);", capitalized_type_name(), number(), property_name()); writer->WriteLine("}"); } void PrimitiveFieldGenerator::WriteHash(Writer* writer) { - if (SupportFieldPresence(descriptor_->file())) { - writer->WriteLine("if (has$0$) {", property_name()); - } else { - writer->WriteLine("if ($0$ != $1$) {", property_name(), default_value()); - } + writer->WriteLine("if ($0$) {", has_property_check); writer->WriteLine(" hash ^= $0$_.GetHashCode();", name()); writer->WriteLine("}"); } @@ -175,13 +168,84 @@ void PrimitiveFieldGenerator::WriteEquals(Writer* writer) { } } void PrimitiveFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$, $2$_, writer);", + descriptor_->name(), has_property_check, name()); +} + +PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : PrimitiveFieldGenerator(descriptor, fieldOrdinal) { + has_property_check = oneof_name() + "Case_ == " + oneof_property_name() + + "OneofCase." + property_name(); +} + +PrimitiveOneofFieldGenerator::~PrimitiveOneofFieldGenerator() { +} + +void PrimitiveOneofFieldGenerator::GenerateMembers(Writer* writer) { + AddDeprecatedFlag(writer); if (SupportFieldPresence(descriptor_->file())) { - writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);", - descriptor_->name(), property_name(), name()); - } else { - writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", - descriptor_->name(), name()); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return $0$; }", has_property_check); + writer->WriteLine("}"); } + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$ ? ($1$) $2$_ : $3$; }", + has_property_check, type_name(), oneof_name(), default_value()); + writer->WriteLine("}"); +} + +void PrimitiveOneofFieldGenerator::GenerateBuilderMembers(Writer* writer) { + AddDeprecatedFlag(writer); + if (SupportFieldPresence(descriptor_->file())) { + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.$0$; }", has_property_check); + writer->WriteLine("}"); + } + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$ ? ($1$) result.$2$_ : $3$; }", + has_property_check, type_name(), oneof_name(), default_value()); + writer->WriteLine(" set { Set$0$(value); }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public Builder Set$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_ = value;", oneof_name()); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.$2$;", + oneof_name(), oneof_property_name(), property_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" if (result.$0$) {", has_property_check); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.None;", + oneof_name(), oneof_property_name()); + writer->WriteLine(" }"); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void PrimitiveOneofFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if (!$0$.Equals(other.$0$)) return false;", property_name()); +} +void PrimitiveOneofFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$, $2$_, writer);", + descriptor_->name(), has_property_check, oneof_name()); +} + +void PrimitiveOneofFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("$0$ value = $1$;", type_name(), default_value()); + writer->WriteLine("if (input.Read$0$(ref value)) {", + capitalized_type_name()); + writer->WriteLine(" result.$0$_ = value;", oneof_name()); + writer->WriteLine(" result.$0$Case_ = $1$OneofCase.$2$;", + oneof_name(), oneof_property_name(), property_name()); + writer->WriteLine("}"); } } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h index fb27ab43..ecc6ed91 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h @@ -60,10 +60,28 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase { virtual void WriteEquals(Writer* writer); virtual void WriteToString(Writer* writer); + protected: + string has_property_check; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); }; +class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { + public: + PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~PrimitiveOneofFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator); +}; + } // namespace csharp } // namespace compiler } // namespace protobuf -- cgit v1.2.3