From bfee2dfe137b07e64ebd46baf71d932d58d01b1f Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Tue, 23 Jun 2015 16:09:27 +0100 Subject: Implement freezing for messages and repeated fields. Fixes issue #523. --- .../protobuf/compiler/csharp/csharp_field_base.cc | 5 +++ .../protobuf/compiler/csharp/csharp_field_base.h | 1 + .../protobuf/compiler/csharp/csharp_message.cc | 36 +++++++++++++++++++++- .../protobuf/compiler/csharp/csharp_message.h | 1 + .../compiler/csharp/csharp_message_field.cc | 13 ++++++-- .../compiler/csharp/csharp_message_field.h | 1 + .../compiler/csharp/csharp_primitive_field.cc | 15 ++++++--- .../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, 82 insertions(+), 8 deletions(-) (limited to 'src/google') diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc index 54f281ee..0bfbc70e 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -107,6 +107,11 @@ FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor, FieldGeneratorBase::~FieldGeneratorBase() { } +void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) { + // No-op: only message fields and repeated fields need + // special handling for freezing, so default to not generating any code. +} + void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) { if (descriptor_->options().deprecated()) { diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h index 91ae3ba1..abf9254b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -48,6 +48,7 @@ class FieldGeneratorBase : public SourceGeneratorBase { ~FieldGeneratorBase(); virtual void GenerateCloningCode(io::Printer* printer) = 0; + virtual void GenerateFreezingCode(io::Printer* printer); 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 39938fa3..9580c167 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -211,7 +211,9 @@ void MessageGenerator::Generate(io::Printer* printer) { "public pb::FieldAccess.FieldAccessorTable<$class_name$> Fields {\n" " get { return $umbrella_class_name$.internal__$identifier$__FieldAccessorTable; }\n" "}\n" - "\n"); + "\n" + "private bool _frozen = false;\n" + "public bool IsFrozen { get { return _frozen; } }\n\n"); // Parameterless constructor printer->Print( @@ -219,6 +221,7 @@ void MessageGenerator::Generate(io::Printer* printer) { "public $class_name$() { }\n\n"); GenerateCloningCode(printer); + GenerateFreezingCode(printer); // Fields/properties for (int i = 0; i < descriptor_->field_count(); i++) { @@ -260,6 +263,7 @@ void MessageGenerator::Generate(io::Printer* printer) { " get { return $name$Case_; }\n" "}\n\n" "public void Clear$property_name$() {\n" + " pb::Freezable.CheckMutable(this);\n" " $name$Case_ = $property_name$OneofCase.None;\n" " $name$_ = null;\n" "}\n\n"); @@ -346,6 +350,36 @@ void MessageGenerator::GenerateCloningCode(io::Printer* printer) { "}\n\n"); } +void MessageGenerator::GenerateFreezingCode(io::Printer* printer) { + map vars; + vars["class_name"] = class_name(); + printer->Print( + "public void Freeze() {\n" + " if (IsFrozen) {\n" + " return;\n" + " }\n" + " _frozen = true;\n"); + printer->Indent(); + // Freeze non-oneof fields first (only messages and repeated fields will actually generate any code) + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + scoped_ptr generator( + CreateFieldGeneratorInternal(descriptor_->field(i))); + generator->GenerateFreezingCode(printer); + } + } + + // For each oneof, if the value is freezable, freeze it. We don't actually need to know which type it was. + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); + printer->Print(vars, + "if ($name$_ is IFreezable) ((IFreezable) $name$_).Freeze();\n"); + } + + printer->Outdent(); + printer->Print("}\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 c3a37a0e..6c7153aa 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.h +++ b/src/google/protobuf/compiler/csharp/csharp_message.h @@ -51,6 +51,7 @@ class MessageGenerator : public SourceGeneratorBase { ~MessageGenerator(); void GenerateCloningCode(io::Printer* printer); + void GenerateFreezingCode(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 82deef54..cbf182d2 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -66,7 +66,10 @@ void MessageFieldGenerator::GenerateMembers(io::Printer* printer) { variables_, "public $type_name$ $property_name$ {\n" " get { return $name$_; }\n" - " set { $name$_ = value; }\n" + " set {\n" + " pb::Freezable.CheckMutable(this);\n" + " $name$_ = value;\n" + " }\n" "}\n"); } @@ -116,7 +119,7 @@ void MessageFieldGenerator::WriteHash(io::Printer* printer) { void MessageFieldGenerator::WriteEquals(io::Printer* printer) { printer->Print( variables_, - "if (!object.Equals($property_name$, other.$property_name$)) return false;"); + "if (!object.Equals($property_name$, other.$property_name$)) return false;\n"); } void MessageFieldGenerator::WriteToString(io::Printer* printer) { variables_["field_name"] = GetFieldName(descriptor_); @@ -130,6 +133,11 @@ void MessageFieldGenerator::GenerateCloningCode(io::Printer* printer) { "$property_name$ = other.$has_property_check$ ? other.$property_name$.Clone() : null;\n"); } +void MessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) { + printer->Print(variables_, + "if ($has_property_check$) $property_name$.Freeze();\n"); +} + MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal) : MessageFieldGenerator(descriptor, fieldOrdinal) { @@ -147,6 +155,7 @@ void MessageOneofFieldGenerator::GenerateMembers(io::Printer* printer) { "public $type_name$ $property_name$ {\n" " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : null; }\n" " set {\n" + " pb::Freezable.CheckMutable(this);\n" " $oneof_name$_ = value;\n" " $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n" " }\n" diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h index f15e8e7e..3e17f92a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h @@ -47,6 +47,7 @@ class MessageFieldGenerator : public FieldGeneratorBase { ~MessageFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); + virtual void GenerateFreezingCode(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_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc index c426c37a..d5542f57 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -72,17 +72,21 @@ void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) { printer->Print( variables_, "public $type_name$ $property_name$ {\n" - " get { return $name$_; }\n"); + " get { return $name$_; }\n" + " set {\n" + " pb::Freezable.CheckMutable(this);\n"); if (is_value_type) { printer->Print( variables_, - " set { $name$_ = value; }\n"); + " $name$_ = value;\n"); } else { printer->Print( variables_, - " set { $name$_ = value ?? $default_value$; }\n"); + " $name$_ = value ?? $default_value$;\n"); } - printer->Print("}\n\n"); + printer->Print( + " }\n" + "}\n"); } void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) { @@ -166,7 +170,8 @@ void PrimitiveOneofFieldGenerator::GenerateMembers(io::Printer* printer) { variables_, "public $type_name$ $property_name$ {\n" " get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : $default_value$; }\n" - " set {\n"); + " set {\n" + " pb::Freezable.CheckMutable(this);\n"); if (is_value_type) { printer->Print( variables_, 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 ce526b37..d223273c 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc @@ -147,6 +147,11 @@ void RepeatedEnumFieldGenerator::GenerateCloningCode(io::Printer* printer) { "$name$_ = other.$name$_.Clone();\n"); } +void RepeatedEnumFieldGenerator::GenerateFreezingCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_.Freeze();\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 c7846a61..ee50eef0 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h @@ -49,6 +49,7 @@ class RepeatedEnumFieldGenerator : public FieldGeneratorBase { ~RepeatedEnumFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); + virtual void GenerateFreezingCode(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 edfb98b4..400f0e4f 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc @@ -123,6 +123,11 @@ void RepeatedMessageFieldGenerator::GenerateCloningCode(io::Printer* printer) { "$name$_ = other.$name$_.Clone();\n"); } +void RepeatedMessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_.Freeze();\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 38006731..cf601c7e 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h @@ -47,6 +47,7 @@ class RepeatedMessageFieldGenerator : public FieldGeneratorBase { ~RepeatedMessageFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); + virtual void GenerateFreezingCode(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 49a29c55..a78a74c0 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc @@ -153,6 +153,11 @@ void RepeatedPrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) "$name$_ = other.$name$_.Clone();\n"); } +void RepeatedPrimitiveFieldGenerator::GenerateFreezingCode(io::Printer* printer) { + printer->Print(variables_, + "$name$_.Freeze();\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 7f8f17a8..f1ceeb50 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h @@ -47,6 +47,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase { ~RepeatedPrimitiveFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); + virtual void GenerateFreezingCode(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