Index: third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_message.cc |
diff --git a/third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_message.cc b/third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_message.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e0230a244b4cc5f531b1f38d9b76812c1a6ef459 |
--- /dev/null |
+++ b/third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_message.cc |
@@ -0,0 +1,499 @@ |
+// Protocol Buffers - Google's data interchange format |
+// Copyright 2008 Google Inc. All rights reserved. |
+// https://developers.google.com/protocol-buffers/ |
+// |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
+// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following disclaimer |
+// in the documentation and/or other materials provided with the |
+// distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived from |
+// this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ |
+#include <sstream> |
+#include <algorithm> |
+#include <map> |
+ |
+#include <google/protobuf/compiler/code_generator.h> |
+#include <google/protobuf/compiler/plugin.h> |
+#include <google/protobuf/descriptor.h> |
+#include <google/protobuf/descriptor.pb.h> |
+#include <google/protobuf/io/printer.h> |
+#include <google/protobuf/io/zero_copy_stream.h> |
+#include <google/protobuf/stubs/strutil.h> |
+#include <google/protobuf/wire_format.h> |
+#include <google/protobuf/wire_format_lite.h> |
+ |
+#include <google/protobuf/compiler/csharp/csharp_doc_comment.h> |
+#include <google/protobuf/compiler/csharp/csharp_enum.h> |
+#include <google/protobuf/compiler/csharp/csharp_field_base.h> |
+#include <google/protobuf/compiler/csharp/csharp_helpers.h> |
+#include <google/protobuf/compiler/csharp/csharp_message.h> |
+#include <google/protobuf/compiler/csharp/csharp_names.h> |
+ |
+using google::protobuf::internal::scoped_ptr; |
+ |
+namespace google { |
+namespace protobuf { |
+namespace compiler { |
+namespace csharp { |
+ |
+bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { |
+ return d1->number() < d2->number(); |
+} |
+ |
+MessageGenerator::MessageGenerator(const Descriptor* descriptor) |
+ : SourceGeneratorBase(descriptor->file()), |
+ descriptor_(descriptor) { |
+ |
+ // sorted field names |
+ for (int i = 0; i < descriptor_->field_count(); i++) { |
+ field_names_.push_back(descriptor_->field(i)->name()); |
+ } |
+ std::sort(field_names_.begin(), field_names_.end()); |
+ |
+ // fields by number |
+ for (int i = 0; i < descriptor_->field_count(); i++) { |
+ fields_by_number_.push_back(descriptor_->field(i)); |
+ } |
+ std::sort(fields_by_number_.begin(), fields_by_number_.end(), |
+ CompareFieldNumbers); |
+} |
+ |
+MessageGenerator::~MessageGenerator() { |
+} |
+ |
+std::string MessageGenerator::class_name() { |
+ return descriptor_->name(); |
+} |
+ |
+std::string MessageGenerator::full_class_name() { |
+ return GetClassName(descriptor_); |
+} |
+ |
+const std::vector<std::string>& MessageGenerator::field_names() { |
+ return field_names_; |
+} |
+ |
+const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() { |
+ return fields_by_number_; |
+} |
+ |
+void MessageGenerator::Generate(io::Printer* printer) { |
+ map<string, string> vars; |
+ vars["class_name"] = class_name(); |
+ vars["access_level"] = class_access_level(); |
+ |
+ WriteMessageDocComment(printer, descriptor_); |
+ printer->Print( |
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n"); |
+ WriteGeneratedCodeAttributes(printer); |
+ printer->Print( |
+ vars, |
+ "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$> {\n"); |
+ printer->Indent(); |
+ |
+ // All static fields and properties |
+ printer->Print( |
+ vars, |
+ "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n" |
+ "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n"); |
+ |
+ // Access the message descriptor via the relevant file descriptor or containing message descriptor. |
+ if (!descriptor_->containing_type()) { |
+ vars["descriptor_accessor"] = GetReflectionClassName(descriptor_->file()) |
+ + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]"; |
+ } else { |
+ vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type()) |
+ + ".Descriptor.NestedTypes[" + SimpleItoa(descriptor_->index()) + "]"; |
+ } |
+ |
+ printer->Print( |
+ vars, |
+ "public static pbr::MessageDescriptor Descriptor {\n" |
+ " get { return $descriptor_accessor$; }\n" |
+ "}\n" |
+ "\n" |
+ "pbr::MessageDescriptor pb::IMessage.Descriptor {\n" |
+ " get { return Descriptor; }\n" |
+ "}\n" |
+ "\n"); |
+ |
+ // Parameterless constructor and partial OnConstruction method. |
+ printer->Print( |
+ vars, |
+ "public $class_name$() {\n" |
+ " OnConstruction();\n" |
+ "}\n\n" |
+ "partial void OnConstruction();\n\n"); |
+ |
+ GenerateCloningCode(printer); |
+ GenerateFreezingCode(printer); |
+ |
+ // Fields/properties |
+ for (int i = 0; i < descriptor_->field_count(); i++) { |
+ const FieldDescriptor* fieldDescriptor = descriptor_->field(i); |
+ |
+ // Rats: we lose the debug comment here :( |
+ printer->Print( |
+ "/// <summary>Field number for the \"$field_name$\" field.</summary>\n" |
+ "public const int $field_constant_name$ = $index$;\n", |
+ "field_name", fieldDescriptor->name(), |
+ "field_constant_name", GetFieldConstantName(fieldDescriptor), |
+ "index", SimpleItoa(fieldDescriptor->number())); |
+ scoped_ptr<FieldGeneratorBase> generator( |
+ CreateFieldGeneratorInternal(fieldDescriptor)); |
+ generator->GenerateMembers(printer); |
+ printer->Print("\n"); |
+ } |
+ |
+ // oneof properties |
+ 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); |
+ vars["original_name"] = descriptor_->oneof_decl(i)->name(); |
+ printer->Print( |
+ vars, |
+ "private object $name$_;\n" |
+ "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n" |
+ "public enum $property_name$OneofCase {\n"); |
+ printer->Indent(); |
+ printer->Print("None = 0,\n"); |
+ for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { |
+ const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); |
+ printer->Print("$field_property_name$ = $index$,\n", |
+ "field_property_name", GetPropertyName(field), |
+ "index", SimpleItoa(field->number())); |
+ } |
+ printer->Outdent(); |
+ printer->Print("}\n"); |
+ // TODO: Should we put the oneof .proto comments here? It's unclear exactly where they should go. |
+ printer->Print( |
+ vars, |
+ "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n" |
+ "public $property_name$OneofCase $property_name$Case {\n" |
+ " get { return $name$Case_; }\n" |
+ "}\n\n" |
+ "public void Clear$property_name$() {\n" |
+ " $name$Case_ = $property_name$OneofCase.None;\n" |
+ " $name$_ = null;\n" |
+ "}\n\n"); |
+ } |
+ |
+ // Standard methods |
+ GenerateFrameworkMethods(printer); |
+ GenerateMessageSerializationMethods(printer); |
+ GenerateMergingMethods(printer); |
+ |
+ // Nested messages and enums |
+ if (HasNestedGeneratedTypes()) { |
+ printer->Print( |
+ vars, |
+ "#region Nested types\n" |
+ "/// <summary>Container for nested types declared in the $class_name$ message type.</summary>\n" |
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n"); |
+ WriteGeneratedCodeAttributes(printer); |
+ printer->Print("public static partial class Types {\n"); |
+ printer->Indent(); |
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) { |
+ EnumGenerator enumGenerator(descriptor_->enum_type(i)); |
+ enumGenerator.Generate(printer); |
+ } |
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) { |
+ // Don't generate nested types for maps... |
+ if (!IsMapEntryMessage(descriptor_->nested_type(i))) { |
+ MessageGenerator messageGenerator(descriptor_->nested_type(i)); |
+ messageGenerator.Generate(printer); |
+ } |
+ } |
+ printer->Outdent(); |
+ printer->Print("}\n" |
+ "#endregion\n" |
+ "\n"); |
+ } |
+ |
+ printer->Outdent(); |
+ printer->Print("}\n"); |
+ printer->Print("\n"); |
+} |
+ |
+// Helper to work out whether we need to generate a class to hold nested types/enums. |
+// Only tricky because we don't want to generate map entry types. |
+bool MessageGenerator::HasNestedGeneratedTypes() |
+{ |
+ if (descriptor_->enum_type_count() > 0) { |
+ return true; |
+ } |
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) { |
+ if (!IsMapEntryMessage(descriptor_->nested_type(i))) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+void MessageGenerator::GenerateCloningCode(io::Printer* printer) { |
+ map<string, string> vars; |
+ vars["class_name"] = class_name(); |
+ printer->Print( |
+ vars, |
+ "public $class_name$($class_name$ other) : this() {\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<FieldGeneratorBase> 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<FieldGeneratorBase> 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::GenerateFreezingCode(io::Printer* printer) { |
+} |
+ |
+void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) { |
+ map<string, string> vars; |
+ vars["class_name"] = class_name(); |
+ |
+ // Equality |
+ printer->Print( |
+ vars, |
+ "public override bool Equals(object other) {\n" |
+ " return Equals(other as $class_name$);\n" |
+ "}\n\n" |
+ "public bool Equals($class_name$ other) {\n" |
+ " if (ReferenceEquals(other, null)) {\n" |
+ " return false;\n" |
+ " }\n" |
+ " if (ReferenceEquals(other, this)) {\n" |
+ " return true;\n" |
+ " }\n"); |
+ printer->Indent(); |
+ for (int i = 0; i < descriptor_->field_count(); i++) { |
+ scoped_ptr<FieldGeneratorBase> generator( |
+ CreateFieldGeneratorInternal(descriptor_->field(i))); |
+ generator->WriteEquals(printer); |
+ } |
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { |
+ printer->Print("if ($property_name$Case != other.$property_name$Case) return false;\n", |
+ "property_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true)); |
+ } |
+ printer->Outdent(); |
+ printer->Print( |
+ " return true;\n" |
+ "}\n\n"); |
+ |
+ // GetHashCode |
+ // Start with a non-zero value to easily distinguish between null and "empty" messages. |
+ printer->Print( |
+ "public override int GetHashCode() {\n" |
+ " int hash = 1;\n"); |
+ printer->Indent(); |
+ for (int i = 0; i < descriptor_->field_count(); i++) { |
+ scoped_ptr<FieldGeneratorBase> generator( |
+ CreateFieldGeneratorInternal(descriptor_->field(i))); |
+ generator->WriteHash(printer); |
+ } |
+ for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { |
+ printer->Print("hash ^= (int) $name$Case_;\n", |
+ "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false)); |
+ } |
+ printer->Print("return hash;\n"); |
+ printer->Outdent(); |
+ printer->Print("}\n\n"); |
+ |
+ printer->Print( |
+ "public override string ToString() {\n" |
+ " return pb::JsonFormatter.ToDiagnosticString(this);\n" |
+ "}\n\n"); |
+} |
+ |
+void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) { |
+ printer->Print( |
+ "public void WriteTo(pb::CodedOutputStream output) {\n"); |
+ printer->Indent(); |
+ |
+ // Serialize all the fields |
+ for (int i = 0; i < fields_by_number().size(); i++) { |
+ scoped_ptr<FieldGeneratorBase> generator( |
+ CreateFieldGeneratorInternal(fields_by_number()[i])); |
+ generator->GenerateSerializationCode(printer); |
+ } |
+ |
+ // TODO(jonskeet): Memoize size of frozen messages? |
+ printer->Outdent(); |
+ printer->Print( |
+ "}\n" |
+ "\n" |
+ "public int CalculateSize() {\n"); |
+ printer->Indent(); |
+ printer->Print("int size = 0;\n"); |
+ for (int i = 0; i < descriptor_->field_count(); i++) { |
+ scoped_ptr<FieldGeneratorBase> generator( |
+ CreateFieldGeneratorInternal(descriptor_->field(i))); |
+ generator->GenerateSerializedSizeCode(printer); |
+ } |
+ printer->Print("return size;\n"); |
+ printer->Outdent(); |
+ printer->Print("}\n\n"); |
+} |
+ |
+void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { |
+ // Note: These are separate from GenerateMessageSerializationMethods() |
+ // because they need to be generated even for messages that are optimized |
+ // for code size. |
+ map<string, string> vars; |
+ vars["class_name"] = class_name(); |
+ |
+ printer->Print( |
+ vars, |
+ "public void MergeFrom($class_name$ other) {\n"); |
+ printer->Indent(); |
+ printer->Print( |
+ "if (other == null) {\n" |
+ " return;\n" |
+ "}\n"); |
+ // Merge non-oneof fields |
+ for (int i = 0; i < descriptor_->field_count(); i++) { |
+ if (!descriptor_->field(i)->containing_oneof()) { |
+ scoped_ptr<FieldGeneratorBase> generator( |
+ CreateFieldGeneratorInternal(descriptor_->field(i))); |
+ generator->GenerateMergingCode(printer); |
+ } |
+ } |
+ // Merge oneof fields |
+ 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); |
+ 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"); |
+ } |
+ printer->Outdent(); |
+ printer->Print("}\n\n"); |
+ } |
+ printer->Outdent(); |
+ printer->Print("}\n\n"); |
+ printer->Print("public void MergeFrom(pb::CodedInputStream input) {\n"); |
+ printer->Indent(); |
+ printer->Print( |
+ "uint tag;\n" |
+ "while ((tag = input.ReadTag()) != 0) {\n" |
+ " switch(tag) {\n"); |
+ printer->Indent(); |
+ printer->Indent(); |
+ printer->Print( |
+ "default:\n" |
+ " input.SkipLastField();\n" // We're not storing the data, but we still need to consume it. |
+ " break;\n"); |
+ for (int i = 0; i < fields_by_number().size(); i++) { |
+ const FieldDescriptor* field = fields_by_number()[i]; |
+ internal::WireFormatLite::WireType wt = |
+ internal::WireFormat::WireTypeForFieldType(field->type()); |
+ uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt); |
+ // Handle both packed and unpacked repeated fields with the same Read*Array call; |
+ // the two generated cases are the packed and unpacked tags. |
+ // TODO(jonskeet): Check that is_packable is equivalent to is_repeated && wt in { VARINT, FIXED32, FIXED64 }. |
+ // It looks like it is... |
+ if (field->is_packable()) { |
+ printer->Print( |
+ "case $packed_tag$:\n", |
+ "packed_tag", |
+ SimpleItoa( |
+ internal::WireFormatLite::MakeTag( |
+ field->number(), |
+ internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED))); |
+ } |
+ |
+ printer->Print("case $tag$: {\n", "tag", SimpleItoa(tag)); |
+ printer->Indent(); |
+ scoped_ptr<FieldGeneratorBase> generator( |
+ CreateFieldGeneratorInternal(field)); |
+ generator->GenerateParsingCode(printer); |
+ printer->Print("break;\n"); |
+ printer->Outdent(); |
+ printer->Print("}\n"); |
+ } |
+ printer->Outdent(); |
+ printer->Print("}\n"); // switch |
+ printer->Outdent(); |
+ printer->Print("}\n"); // while |
+ printer->Outdent(); |
+ printer->Print("}\n\n"); // method |
+} |
+ |
+int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) { |
+ for (int i = 0; i < field_names().size(); i++) { |
+ if (field_names()[i] == descriptor->name()) { |
+ return i; |
+ } |
+ } |
+ GOOGLE_LOG(DFATAL)<< "Could not find ordinal for field " << descriptor->name(); |
+ return -1; |
+} |
+ |
+FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal( |
+ const FieldDescriptor* descriptor) { |
+ return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor)); |
+} |
+ |
+} // namespace csharp |
+} // namespace compiler |
+} // namespace protobuf |
+} // namespace google |