aboutsummaryrefslogtreecommitdiff
path: root/src/google/protobuf/compiler/csharp/csharp_message.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/compiler/csharp/csharp_message.cc')
-rw-r--r--src/google/protobuf/compiler/csharp/csharp_message.cc894
1 files changed, 894 insertions, 0 deletions
diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc
new file mode 100644
index 00000000..96f7c17c
--- /dev/null
+++ b/src/google/protobuf/compiler/csharp/csharp_message.cc
@@ -0,0 +1,894 @@
+// 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 <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_enum.h>
+#include <google/protobuf/compiler/csharp/csharp_extension.h>
+#include <google/protobuf/compiler/csharp/csharp_message.h>
+#include <google/protobuf/compiler/csharp/csharp_helpers.h>
+#include <google/protobuf/compiler/csharp/csharp_field_base.h>
+#include <google/protobuf/compiler/csharp/csharp_writer.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_;
+}
+
+/// Get an identifier that uniquely identifies this type within the file.
+/// This is used to declare static variables related to this type at the
+/// outermost file scope.
+std::string GetUniqueFileScopeIdentifier(const Descriptor* descriptor) {
+ std::string result = descriptor->full_name();
+ std::replace(result.begin(), result.end(), '.', '_');
+ return "static_" + result;
+}
+
+void MessageGenerator::GenerateStaticVariables(Writer* writer) {
+ // Because descriptor.proto (Google.ProtocolBuffers.DescriptorProtos) is
+ // used in the construction of descriptors, we have a tricky bootstrapping
+ // problem. To help control static initialization order, we make sure all
+ // descriptors and other static data that depends on them are members of
+ // the proto-descriptor class. This way, they will be initialized in
+ // a deterministic order.
+
+ std::string identifier = GetUniqueFileScopeIdentifier(descriptor_);
+
+ if (!use_lite_runtime()) {
+ // The descriptor for this type.
+ std::string access = "internal";
+ writer->WriteLine(
+ "$0$ static pbd::MessageDescriptor internal__$1$__Descriptor;", access,
+ identifier);
+ writer->WriteLine(
+ "$0$ static pb::FieldAccess.FieldAccessorTable<$1$, $1$.Builder> internal__$2$__FieldAccessorTable;",
+ access, full_class_name(), identifier);
+ }
+
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ MessageGenerator messageGenerator(descriptor_->nested_type(i));
+ messageGenerator.GenerateStaticVariables(writer);
+ }
+}
+
+void MessageGenerator::GenerateStaticVariableInitializers(Writer* writer) {
+ std::string identifier = GetUniqueFileScopeIdentifier(descriptor_);
+
+ if (!use_lite_runtime()) {
+ writer->Write("internal__$0$__Descriptor = ", identifier);
+
+ if (!descriptor_->containing_type()) {
+ writer->WriteLine("Descriptor.MessageTypes[$0$];",
+ SimpleItoa(descriptor_->index()));
+ } else {
+ writer->WriteLine(
+ "internal__$0$__Descriptor.NestedTypes[$1$];",
+ GetUniqueFileScopeIdentifier(descriptor_->containing_type()),
+ SimpleItoa(descriptor_->index()));
+ }
+
+ writer->WriteLine("internal__$0$__FieldAccessorTable = ", identifier);
+ writer->WriteLine(
+ " new pb::FieldAccess.FieldAccessorTable<$1$, $1$.Builder>(internal__$0$__Descriptor,",
+ identifier, full_class_name());
+ writer->Write(" new string[] { ");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ writer->Write("\"$0$\", ", GetPropertyName(descriptor_->field(i)));
+ }
+ writer->WriteLine("});");
+ }
+
+ // Generate static member initializers for all nested types.
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ MessageGenerator messageGenerator(descriptor_->nested_type(i));
+ messageGenerator.GenerateStaticVariableInitializers(writer);
+ }
+
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ExtensionGenerator extensionGenerator(descriptor_->extension(i));
+ extensionGenerator.GenerateStaticVariableInitializers(writer);
+ }
+}
+
+void MessageGenerator::Generate(Writer* writer) {
+ writer->WriteLine(
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer->WriteLine(
+ "$0$ sealed partial class $1$ : pb::$2$Message$3$<$1$, $1$.Builder> {",
+ class_access_level(), class_name(),
+ descriptor_->extension_range_count() > 0 ? "Extendable" : "Generated",
+ runtime_suffix());
+ writer->Indent();
+ writer->WriteLine("private $0$() { }", class_name()); // Private ctor.
+ // Must call MakeReadOnly() to make sure all lists are made read-only
+ writer->WriteLine(
+ "private static readonly $0$ defaultInstance = new $0$().MakeReadOnly();",
+ class_name());
+
+ if (optimize_speed()) {
+ writer->WriteLine(
+ "private static readonly string[] _$0$FieldNames = new string[] { $2$$1$$2$ };",
+ UnderscoresToCamelCase(class_name(), false),
+ JoinStrings(field_names(), "\", \""),
+ field_names().size() > 0 ? "\"" : "");
+ std::vector<std::string> tags;
+ for (int i = 0; i < field_names().size(); i++) {
+ uint32 tag = internal::WireFormat::MakeTag(
+ descriptor_->FindFieldByName(field_names()[i]));
+ tags.push_back(SimpleItoa(tag));
+ }
+ writer->WriteLine(
+ "private static readonly uint[] _$0$FieldTags = new uint[] { $1$ };",
+ UnderscoresToCamelCase(class_name(), false), JoinStrings(tags, ", "));
+ }
+ writer->WriteLine("public static $0$ DefaultInstance {", class_name());
+ writer->WriteLine(" get { return defaultInstance; }");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine("public override $0$ DefaultInstanceForType {",
+ class_name());
+ writer->WriteLine(" get { return DefaultInstance; }");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine("protected override $0$ ThisMessage {", class_name());
+ writer->WriteLine(" get { return this; }");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ if (!use_lite_runtime()) {
+ writer->WriteLine("public static pbd::MessageDescriptor Descriptor {");
+ writer->WriteLine(" get { return $0$.internal__$1$__Descriptor; }",
+ GetFullUmbrellaClassName(descriptor_->file()),
+ GetUniqueFileScopeIdentifier(descriptor_));
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine(
+ "protected override pb::FieldAccess.FieldAccessorTable<$0$, $0$.Builder> InternalFieldAccessors {",
+ class_name());
+ writer->WriteLine(" get { return $0$.internal__$1$__FieldAccessorTable; }",
+ GetFullUmbrellaClassName(descriptor_->file()),
+ GetUniqueFileScopeIdentifier(descriptor_));
+ writer->WriteLine("}");
+ writer->WriteLine();
+ }
+
+ // Extensions don't need to go in an extra nested type
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ExtensionGenerator extensionGenerator(descriptor_->extension(i));
+ extensionGenerator.Generate(writer);
+ }
+
+ if (descriptor_->enum_type_count() + descriptor_->nested_type_count() > 0) {
+ writer->WriteLine("#region Nested types");
+ writer->WriteLine(
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer->WriteLine("public static partial class Types {");
+ writer->Indent();
+ for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+ EnumGenerator enumGenerator(descriptor_->enum_type(i));
+ enumGenerator.Generate(writer);
+ }
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ MessageGenerator messageGenerator(descriptor_->nested_type(i));
+ messageGenerator.Generate(writer);
+ }
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine("#endregion");
+ writer->WriteLine();
+ }
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
+
+ // Rats: we lose the debug comment here :(
+ writer->WriteLine("public const int $0$ = $1$;",
+ GetFieldConstantName(fieldDescriptor),
+ SimpleItoa(fieldDescriptor->number()));
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(fieldDescriptor));
+ generator->GenerateMembers(writer);
+ writer->WriteLine();
+ }
+
+ if (optimize_speed()) {
+ if (SupportFieldPresence(descriptor_->file())) {
+ GenerateIsInitialized(writer);
+ }
+ GenerateMessageSerializationMethods(writer);
+ }
+ if (use_lite_runtime()) {
+ GenerateLiteRuntimeMethods(writer);
+ }
+
+ GenerateParseFromMethods(writer);
+ GenerateBuilder(writer);
+
+ // Force the static initialization code for the file to run, since it may
+ // initialize static variables declared in this class.
+ writer->WriteLine("static $0$() {", class_name());
+ // We call object.ReferenceEquals() just to make it a valid statement on its own.
+ // Another option would be GetType(), but that causes problems in DescriptorProtoFile,
+ // where the bootstrapping is somewhat recursive - type initializers call
+ // each other, effectively. We temporarily see Descriptor as null.
+ writer->WriteLine(" object.ReferenceEquals($0$.Descriptor, null);",
+ GetFullUmbrellaClassName(descriptor_->file()));
+ writer->WriteLine("}");
+
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+
+}
+
+void MessageGenerator::GenerateLiteRuntimeMethods(Writer* writer) {
+ bool callbase = descriptor_->extension_range_count() > 0;
+ writer->WriteLine("#region Lite runtime methods");
+ writer->WriteLine("public override int GetHashCode() {");
+ writer->Indent();
+ writer->WriteLine("int hash = GetType().GetHashCode();");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->WriteHash(writer);
+ }
+ if (callbase) {
+ writer->WriteLine("hash ^= base.GetHashCode();");
+ }
+ writer->WriteLine("return hash;");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+
+ writer->WriteLine("public override bool Equals(object obj) {");
+ writer->Indent();
+ writer->WriteLine("$0$ other = obj as $0$;", class_name());
+ writer->WriteLine("if (other == null) return false;");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->WriteEquals(writer);
+ }
+ if (callbase) {
+ writer->WriteLine("if (!base.Equals(other)) return false;");
+ }
+ writer->WriteLine("return true;");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+
+ writer->WriteLine(
+ "public override void PrintTo(global::System.IO.TextWriter writer) {");
+ writer->Indent();
+
+ for (int i = 0; i < fields_by_number().size(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(fields_by_number()[i]));
+ generator->WriteToString(writer);
+ }
+
+ if (callbase) {
+ writer->WriteLine("base.PrintTo(writer);");
+ }
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine("#endregion");
+ writer->WriteLine();
+}
+
+bool CompareExtensionRangesStart(const Descriptor::ExtensionRange* r1,
+ const Descriptor::ExtensionRange* r2) {
+ return r1->start < r2->start;
+}
+
+void MessageGenerator::GenerateMessageSerializationMethods(Writer* writer) {
+ std::vector<const Descriptor::ExtensionRange*> extension_ranges_sorted;
+ for (int i = 0; i < descriptor_->extension_range_count(); i++) {
+ extension_ranges_sorted.push_back(descriptor_->extension_range(i));
+ }
+ std::sort(extension_ranges_sorted.begin(), extension_ranges_sorted.end(),
+ CompareExtensionRangesStart);
+
+ writer->WriteLine(
+ "public override void WriteTo(pb::ICodedOutputStream output) {");
+ writer->Indent();
+ // Make sure we've computed the serialized length, so that packed fields are generated correctly.
+ writer->WriteLine("CalcSerializedSize();");
+ writer->WriteLine("string[] field_names = _$0$FieldNames;",
+ UnderscoresToCamelCase(class_name(), false));
+ if (descriptor_->extension_range_count()) {
+ writer->WriteLine(
+ "pb::ExtendableMessage$1$<$0$, $0$.Builder>.ExtensionWriter extensionWriter = CreateExtensionWriter(this);",
+ class_name(), runtime_suffix());
+ }
+
+ // Merge the fields and the extension ranges, both sorted by field number.
+ for (int i = 0, j = 0;
+ i < fields_by_number().size() || j < extension_ranges_sorted.size();) {
+ if (i == fields_by_number().size()) {
+ GenerateSerializeOneExtensionRange(writer, extension_ranges_sorted[j++]);
+ } else if (j == extension_ranges_sorted.size()) {
+ GenerateSerializeOneField(writer, fields_by_number()[i++]);
+ } else if (fields_by_number()[i]->number()
+ < extension_ranges_sorted[j]->start) {
+ GenerateSerializeOneField(writer, fields_by_number()[i++]);
+ } else {
+ GenerateSerializeOneExtensionRange(writer, extension_ranges_sorted[j++]);
+ }
+ }
+
+ if (!use_lite_runtime()) {
+ if (descriptor_->options().message_set_wire_format())
+ {
+ writer->WriteLine("UnknownFields.WriteAsMessageSetTo(output);");
+ } else {
+ writer->WriteLine("UnknownFields.WriteTo(output);");
+ }
+ }
+
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine("private int memoizedSerializedSize = -1;");
+ writer->WriteLine("public override int SerializedSize {");
+ writer->Indent();
+ writer->WriteLine("get {");
+ writer->Indent();
+ writer->WriteLine("int size = memoizedSerializedSize;");
+ writer->WriteLine("if (size != -1) return size;");
+ writer->WriteLine("return CalcSerializedSize();");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+
+ writer->WriteLine("private int CalcSerializedSize() {");
+ writer->Indent();
+ writer->WriteLine("int size = memoizedSerializedSize;");
+ writer->WriteLine("if (size != -1) return size;");
+ writer->WriteLine();
+ writer->WriteLine("size = 0;");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->GenerateSerializedSizeCode(writer);
+ }
+ if (descriptor_->extension_range_count() > 0) {
+ writer->WriteLine("size += ExtensionsSerializedSize;");
+ }
+
+ if (!use_lite_runtime()) {
+ if (descriptor_->options().message_set_wire_format()) {
+ writer->WriteLine("size += UnknownFields.SerializedSizeAsMessageSet;");
+ } else {
+ writer->WriteLine("size += UnknownFields.SerializedSize;");
+ }
+ }
+ writer->WriteLine("memoizedSerializedSize = size;");
+ writer->WriteLine("return size;");
+ writer->Outdent();
+ writer->WriteLine("}");
+}
+
+void MessageGenerator::GenerateSerializeOneField(
+ Writer* writer, const FieldDescriptor* fieldDescriptor) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(fieldDescriptor));
+ generator->GenerateSerializationCode(writer);
+}
+
+void MessageGenerator::GenerateSerializeOneExtensionRange(
+ Writer* writer, const Descriptor::ExtensionRange* extensionRange) {
+ writer->WriteLine("extensionWriter.WriteUntil($0$, output);",
+ SimpleItoa(extensionRange->end));
+}
+
+void MessageGenerator::GenerateParseFromMethods(Writer* writer) {
+ // Note: These are separate from GenerateMessageSerializationMethods()
+ // because they need to be generated even for messages that are optimized
+ // for code size.
+
+ writer->WriteLine("public static $0$ ParseFrom(pb::ByteString data) {",
+ class_name());
+ writer->WriteLine(
+ " return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine(
+ "public static $0$ ParseFrom(pb::ByteString data, pb::ExtensionRegistry extensionRegistry) {",
+ class_name());
+ writer->WriteLine(
+ " return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine("public static $0$ ParseFrom(byte[] data) {", class_name());
+ writer->WriteLine(
+ " return ((Builder) CreateBuilder().MergeFrom(data)).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine(
+ "public static $0$ ParseFrom(byte[] data, pb::ExtensionRegistry extensionRegistry) {",
+ class_name());
+ writer->WriteLine(
+ " return ((Builder) CreateBuilder().MergeFrom(data, extensionRegistry)).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine(
+ "public static $0$ ParseFrom(global::System.IO.Stream input) {",
+ class_name());
+ writer->WriteLine(
+ " return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine(
+ "public static $0$ ParseFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {",
+ class_name());
+ writer->WriteLine(
+ " return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine(
+ "public static $0$ ParseDelimitedFrom(global::System.IO.Stream input) {",
+ class_name());
+ writer->WriteLine(
+ " return CreateBuilder().MergeDelimitedFrom(input).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine(
+ "public static $0$ ParseDelimitedFrom(global::System.IO.Stream input, pb::ExtensionRegistry extensionRegistry) {",
+ class_name());
+ writer->WriteLine(
+ " return CreateBuilder().MergeDelimitedFrom(input, extensionRegistry).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine(
+ "public static $0$ ParseFrom(pb::ICodedInputStream input) {",
+ class_name());
+ writer->WriteLine(
+ " return ((Builder) CreateBuilder().MergeFrom(input)).BuildParsed();");
+ writer->WriteLine("}");
+ writer->WriteLine(
+ "public static $0$ ParseFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {",
+ class_name());
+ writer->WriteLine(
+ " return ((Builder) CreateBuilder().MergeFrom(input, extensionRegistry)).BuildParsed();");
+ writer->WriteLine("}");
+}
+
+void MessageGenerator::GenerateBuilder(Writer* writer) {
+ writer->WriteLine("private $0$ MakeReadOnly() {", class_name());
+ writer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->GenerateBuildingCode(writer);
+ }
+ writer->WriteLine("return this;");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+
+ writer->WriteLine(
+ "public static Builder CreateBuilder() { return new Builder(); }");
+ writer->WriteLine(
+ "public override Builder ToBuilder() { return CreateBuilder(this); }");
+ writer->WriteLine(
+ "public override Builder CreateBuilderForType() { return new Builder(); }");
+ writer->WriteLine("public static Builder CreateBuilder($0$ prototype) {",
+ class_name());
+ writer->WriteLine(" return new Builder(prototype);");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine(
+ "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]");
+ WriteGeneratedCodeAttributes(writer);
+ writer->WriteLine(
+ "$0$ sealed partial class Builder : pb::$2$Builder$3$<$1$, Builder> {",
+ class_access_level(), class_name(),
+ descriptor_->extension_range_count() > 0 ? "Extendable" : "Generated",
+ runtime_suffix());
+ writer->Indent();
+ writer->WriteLine("protected override Builder ThisBuilder {");
+ writer->WriteLine(" get { return this; }");
+ writer->WriteLine("}");
+ GenerateCommonBuilderMethods(writer);
+ if (optimize_speed()) {
+ GenerateBuilderParsingMethods(writer);
+ }
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ writer->WriteLine();
+ // No field comment :(
+ generator->GenerateBuilderMembers(writer);
+ }
+ writer->Outdent();
+ writer->WriteLine("}");
+}
+
+void MessageGenerator::GenerateCommonBuilderMethods(Writer* writer) {
+ //default constructor
+ writer->WriteLine("public Builder() {");
+ //Durring static initialization of message, DefaultInstance is expected to return null.
+ writer->WriteLine(" result = DefaultInstance;");
+ writer->WriteLine(" resultIsReadOnly = true;");
+ writer->WriteLine("}");
+ //clone constructor
+ writer->WriteLine("internal Builder($0$ cloneFrom) {", class_name());
+ writer->WriteLine(" result = cloneFrom;");
+ writer->WriteLine(" resultIsReadOnly = true;");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine("private bool resultIsReadOnly;");
+ writer->WriteLine("private $0$ result;", class_name());
+ writer->WriteLine();
+ writer->WriteLine("private $0$ PrepareBuilder() {", class_name());
+ writer->WriteLine(" if (resultIsReadOnly) {");
+ writer->WriteLine(" $0$ original = result;", class_name());
+ writer->WriteLine(" result = new $0$();", class_name());
+ writer->WriteLine(" resultIsReadOnly = false;");
+ writer->WriteLine(" MergeFrom(original);");
+ writer->WriteLine(" }");
+ writer->WriteLine(" return result;");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine("public override bool IsInitialized {");
+ writer->WriteLine(" get { return result.IsInitialized; }");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine("protected override $0$ MessageBeingBuilt {", class_name());
+ writer->WriteLine(" get { return PrepareBuilder(); }");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ //Not actually expecting that DefaultInstance would ever be null here; however, we will ensure it does not break
+ writer->WriteLine("public override Builder Clear() {");
+ writer->WriteLine(" result = DefaultInstance;");
+ writer->WriteLine(" resultIsReadOnly = true;");
+ writer->WriteLine(" return this;");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine("public override Builder Clone() {");
+ writer->WriteLine(" if (resultIsReadOnly) {");
+ writer->WriteLine(" return new Builder(result);");
+ writer->WriteLine(" } else {");
+ writer->WriteLine(" return new Builder().MergeFrom(result);");
+ writer->WriteLine(" }");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ if (!use_lite_runtime()) {
+ writer->WriteLine(
+ "public override pbd::MessageDescriptor DescriptorForType {");
+ writer->WriteLine(" get { return $0$.Descriptor; }", full_class_name());
+ writer->WriteLine("}");
+ writer->WriteLine();
+ }
+ writer->WriteLine("public override $0$ DefaultInstanceForType {",
+ class_name());
+ writer->WriteLine(" get { return $0$.DefaultInstance; }", full_class_name());
+ writer->WriteLine("}");
+ writer->WriteLine();
+
+ writer->WriteLine("public override $0$ BuildPartial() {", class_name());
+ writer->Indent();
+ writer->WriteLine("if (resultIsReadOnly) {");
+ writer->WriteLine(" return result;");
+ writer->WriteLine("}");
+ writer->WriteLine("resultIsReadOnly = true;");
+ writer->WriteLine("return result.MakeReadOnly();");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+
+ if (optimize_speed()) {
+ writer->WriteLine(
+ "public override Builder MergeFrom(pb::IMessage$0$ other) {",
+ runtime_suffix());
+ writer->WriteLine(" if (other is $0$) {", class_name());
+ writer->WriteLine(" return MergeFrom(($0$) other);", class_name());
+ writer->WriteLine(" } else {");
+ writer->WriteLine(" base.MergeFrom(other);");
+ writer->WriteLine(" return this;");
+ writer->WriteLine(" }");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine("public override Builder MergeFrom($0$ other) {",
+ class_name());
+ // Optimization: If other is the default instance, we know none of its
+ // fields are set so we can skip the merge.
+ writer->Indent();
+ writer->WriteLine("if (other == $0$.DefaultInstance) return this;",
+ full_class_name());
+ writer->WriteLine("PrepareBuilder();");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(descriptor_->field(i)));
+ generator->GenerateMergingCode(writer);
+ }
+ // if message type has extensions
+ if (descriptor_->extension_range_count() > 0) {
+ writer->WriteLine(" this.MergeExtensionFields(other);");
+ }
+ if (!use_lite_runtime()) {
+ writer->WriteLine("this.MergeUnknownFields(other.UnknownFields);");
+ }
+ writer->WriteLine("return this;");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+ }
+
+}
+
+void MessageGenerator::GenerateBuilderParsingMethods(Writer* writer) {
+ writer->WriteLine(
+ "public override Builder MergeFrom(pb::ICodedInputStream input) {");
+ writer->WriteLine(" return MergeFrom(input, pb::ExtensionRegistry.Empty);");
+ writer->WriteLine("}");
+ writer->WriteLine();
+ writer->WriteLine(
+ "public override Builder MergeFrom(pb::ICodedInputStream input, pb::ExtensionRegistry extensionRegistry) {");
+ writer->Indent();
+ writer->WriteLine("PrepareBuilder();");
+ if (!use_lite_runtime()) {
+ writer->WriteLine("pb::UnknownFieldSet.Builder unknownFields = null;");
+ }
+ writer->WriteLine("uint tag;");
+ writer->WriteLine("string field_name;");
+ writer->WriteLine("while (input.ReadTag(out tag, out field_name)) {");
+ writer->Indent();
+ writer->WriteLine("if(tag == 0 && field_name != null) {");
+ writer->Indent();
+ //if you change from StringComparer.Ordinal, the array sort in FieldNames { get; } must also change
+ writer->WriteLine(
+ "int field_ordinal = global::System.Array.BinarySearch(_$0$FieldNames, field_name, global::System.StringComparer.Ordinal);",
+ UnderscoresToCamelCase(class_name(), false));
+ writer->WriteLine("if(field_ordinal >= 0)");
+ writer->WriteLine(" tag = _$0$FieldTags[field_ordinal];",
+ UnderscoresToCamelCase(class_name(), false));
+ writer->WriteLine("else {");
+ 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(
+ " ParseUnknownField(input, $0$extensionRegistry, tag, field_name);",
+ use_lite_runtime() ? "" : "unknownFields, ");
+ writer->WriteLine(" continue;");
+ writer->WriteLine("}");
+ writer->Outdent();
+ writer->WriteLine("}");
+
+ writer->WriteLine("switch (tag) {");
+ writer->Indent();
+ writer->WriteLine("case 0: {"); // 0 signals EOF / limit reached
+ writer->WriteLine(" throw pb::InvalidProtocolBufferException.InvalidTag();");
+ writer->WriteLine("}");
+ writer->WriteLine("default: {");
+ writer->WriteLine(" if (pb::WireFormat.IsEndGroupTag(tag)) {");
+ if (!use_lite_runtime()) {
+ writer->WriteLine(" if (unknownFields != null) {");
+ writer->WriteLine(" this.UnknownFields = unknownFields.Build();");
+ writer->WriteLine(" }");
+ }
+ writer->WriteLine(" return this;"); // it's an endgroup tag
+ writer->WriteLine(" }");
+ 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(
+ " ParseUnknownField(input, $0$extensionRegistry, tag, field_name);",
+ use_lite_runtime() ? "" : "unknownFields, ");
+ writer->WriteLine(" break;");
+ writer->WriteLine("}");
+
+ 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);
+ if (field->is_repeated()
+ && (wt == internal::WireFormatLite::WIRETYPE_VARINT
+ || wt == internal::WireFormatLite::WIRETYPE_FIXED32
+ || wt == internal::WireFormatLite::WIRETYPE_FIXED64)) {
+ writer->WriteLine(
+ "case $0$:",
+ SimpleItoa(
+ internal::WireFormatLite::MakeTag(
+ field->number(),
+ internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)));
+ }
+
+ writer->WriteLine("case $0$: {", SimpleItoa(tag));
+ writer->Indent();
+ scoped_ptr<FieldGeneratorBase> generator(
+ CreateFieldGeneratorInternal(field));
+ generator->GenerateParsingCode(writer);
+ writer->WriteLine("break;");
+ writer->Outdent();
+ writer->WriteLine("}");
+ }
+
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+ if (!use_lite_runtime()) {
+ writer->WriteLine("if (unknownFields != null) {");
+ writer->WriteLine(" this.UnknownFields = unknownFields.Build();");
+ writer->WriteLine("}");
+ }
+ writer->WriteLine("return this;");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+}
+
+void MessageGenerator::GenerateIsInitialized(Writer* writer) {
+ writer->WriteLine("public override bool IsInitialized {");
+ writer->Indent();
+ writer->WriteLine("get {");
+ writer->Indent();
+
+ // Check that all required fields in this message are set.
+ // TODO(kenton): We can optimize this when we switch to putting all the
+ // "has" fields into a single bitfield.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (descriptor_->field(i)->is_required()) {
+ writer->WriteLine("if (!has$0$) return false;",
+ GetPropertyName(descriptor_->field(i)));
+ }
+ }
+
+ // Now check that all embedded messages are initialized.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+
+ if (field->type() != FieldDescriptor::TYPE_MESSAGE ||
+ !HasRequiredFields(field->message_type()))
+ {
+ continue;
+ }
+ // TODO(jtattermusch): shouldn't we use GetPropertyName here?
+ string propertyName = UnderscoresToPascalCase(GetFieldName(field));
+ if (field->is_repeated())
+ {
+ writer->WriteLine("foreach ($0$ element in $1$List) {",
+ GetClassName(field->message_type()),
+ propertyName);
+ writer->WriteLine(" if (!element.IsInitialized) return false;");
+ writer->WriteLine("}");
+ }
+ else if (field->is_optional())
+ {
+ writer->WriteLine("if (Has$0$) {", propertyName);
+ writer->WriteLine(" if (!$0$.IsInitialized) return false;", propertyName);
+ writer->WriteLine("}");
+ }
+ else
+ {
+ writer->WriteLine("if (!$0$.IsInitialized) return false;", propertyName);
+ }
+ }
+
+ if (descriptor_->extension_range_count() > 0) {
+ writer->WriteLine("if (!ExtensionsAreInitialized) return false;");
+ }
+ writer->WriteLine("return true;");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->Outdent();
+ writer->WriteLine("}");
+ writer->WriteLine();
+}
+
+void MessageGenerator::GenerateExtensionRegistrationCode(Writer* writer) {
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ExtensionGenerator extensionGenerator(descriptor_->extension(i));
+ extensionGenerator.GenerateExtensionRegistrationCode(writer);
+ }
+ for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ MessageGenerator messageGenerator(descriptor_->nested_type(i));
+ messageGenerator.GenerateExtensionRegistrationCode(writer);
+ }
+}
+
+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