diff options
36 files changed, 5199 insertions, 52 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 8a27b823..59f7eaa2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -126,7 +126,8 @@ nobase_include_HEADERS = \ google/protobuf/compiler/java/java_names.h \ google/protobuf/compiler/javanano/javanano_generator.h \ google/protobuf/compiler/python/python_generator.h \ - google/protobuf/compiler/ruby/ruby_generator.h + google/protobuf/compiler/ruby/ruby_generator.h \ + google/protobuf/compiler/csharp/csharp_generator.h nobase_nodist_include_HEADERS = \ $(public_config) @@ -288,7 +289,22 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/javanano/javanano_primitive_field.cc \ google/protobuf/compiler/javanano/javanano_primitive_field.h \ google/protobuf/compiler/python/python_generator.cc \ - google/protobuf/compiler/ruby/ruby_generator.cc + google/protobuf/compiler/ruby/ruby_generator.cc \ + google/protobuf/compiler/csharp/csharp_enum.cc \ + google/protobuf/compiler/csharp/csharp_enum_field.cc \ + google/protobuf/compiler/csharp/csharp_extension.cc \ + google/protobuf/compiler/csharp/csharp_field_base.cc \ + google/protobuf/compiler/csharp/csharp_generator.cc \ + google/protobuf/compiler/csharp/csharp_helpers.cc \ + google/protobuf/compiler/csharp/csharp_message.cc \ + google/protobuf/compiler/csharp/csharp_message_field.cc \ + google/protobuf/compiler/csharp/csharp_primitive_field.cc \ + google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc \ + google/protobuf/compiler/csharp/csharp_repeated_message_field.cc \ + google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc \ + google/protobuf/compiler/csharp/csharp_source_generator_base.cc \ + google/protobuf/compiler/csharp/csharp_umbrella_class.cc \ + google/protobuf/compiler/csharp/csharp_writer.cc bin_PROGRAMS = protoc protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la @@ -493,6 +509,7 @@ protobuf_test_SOURCES = \ google/protobuf/compiler/java/java_doc_comment_unittest.cc \ google/protobuf/compiler/python/python_plugin_unittest.cc \ google/protobuf/compiler/ruby/ruby_generator_unittest.cc \ + google/protobuf/compiler/csharp/csharp_generator_unittest.cc \ $(COMMON_TEST_SOURCES) nodist_protobuf_test_SOURCES = $(protoc_outputs) diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc new file mode 100644 index 00000000..27643e61 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc @@ -0,0 +1,79 @@ +// 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 <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/compiler/csharp/csharp_enum.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) : + SourceGeneratorBase(descriptor->file()), + descriptor_(descriptor) { +} + +EnumGenerator::~EnumGenerator() { +} + +void EnumGenerator::Generate(Writer* writer) { + WriteGeneratedCodeAttributes(writer); + writer->WriteLine("$0$ enum $1$ {", + class_access_level(), + descriptor_->name()); + writer->Indent(); + for (int i = 0; i < descriptor_->value_count(); i++) { + writer->WriteLine("$0$ = $1$,", + descriptor_->value(i)->name(), + SimpleItoa(descriptor_->value(i)->number())); + } + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine(); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.h b/src/google/protobuf/compiler/csharp/csharp_enum.h new file mode 100644 index 00000000..eaa7a9c5 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_enum.h @@ -0,0 +1,65 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class EnumGenerator : public SourceGeneratorBase { + public: + EnumGenerator(const EnumDescriptor* descriptor); + ~EnumGenerator(); + + void Generate(Writer* writer); + + private: + const EnumDescriptor* descriptor_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc new file mode 100644 index 00000000..d5b1b477 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc @@ -0,0 +1,160 @@ +// 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 <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/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +EnumFieldGenerator::~EnumFieldGenerator() { + +} + +void EnumFieldGenerator::GenerateMembers(Writer* writer) { + writer->WriteLine("private bool has$0$;", property_name()); + writer->WriteLine("private $0$ $1$_ = $2$;", type_name(), name(), + default_value()); + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return has$0$; }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$_; }", name()); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateBuilderMembers(Writer* writer) { + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.has$0$; }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$; }", property_name()); + 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.has$0$ = true;", property_name()); + writer->WriteLine(" result.$0$_ = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.has$0$ = false;", property_name()); + writer->WriteLine(" result.$0$_ = $1$;", name(), default_value()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.Has$0$) {", property_name()); + writer->WriteLine(" $0$ = other.$0$;", property_name()); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateBuildingCode(Writer* writer) { + // Nothing to do here for enum types +} + +void EnumFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("object unknown;"); + writer->WriteLine("if(input.ReadEnum(ref result.$0$_, out unknown)) {", + name()); + writer->WriteLine(" result.has$0$ = true;", 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("}"); +} + +void EnumFieldGenerator::GenerateSerializationCode(Writer* writer) { + writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine( + " output.WriteEnum($0$, field_names[$2$], (int) $1$, $1$);", number(), + property_name(), field_ordinal()); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine( + " size += pb::CodedOutputStream.ComputeEnumSize($0$, (int) $1$);", + number(), property_name()); + writer->WriteLine("}"); +} + +void EnumFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("if (has$0$) hash ^= $1$_.GetHashCode();", property_name(), + name()); +} +void EnumFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine( + "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;", + property_name(), name()); +} +void EnumFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);", + descriptor_->name(), property_name(), name()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_enum_field.h new file mode 100644 index 00000000..b21fa9dc --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class EnumFieldGenerator : public FieldGeneratorBase { + public: + EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~EnumFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_ENUM_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_extension.cc b/src/google/protobuf/compiler/csharp/csharp_extension.cc new file mode 100644 index 00000000..5d38f52e --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_extension.cc @@ -0,0 +1,174 @@ +// 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 <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/compiler/csharp/csharp_extension.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor) + : FieldGeneratorBase(descriptor, 0) { + if (descriptor_->extension_scope()) { + scope_ = GetClassName(descriptor_->extension_scope()); + } else { + scope_ = GetFullUmbrellaClassName(descriptor_->file()); + } + extends_ = GetClassName(descriptor_->containing_type()); +} + +ExtensionGenerator::~ExtensionGenerator() { +} + +void ExtensionGenerator::Generate(Writer* writer) { + if (cls_compliance() + && (GetFieldConstantName(descriptor_).substr(0, 1) == "_")) { + writer->WriteLine("[global::System.CLSCompliant(false)]"); + } + + writer->WriteLine("public const int $0$ = $1$;", + GetFieldConstantName(descriptor_), + SimpleItoa(descriptor_->number())); + + if (use_lite_runtime()) { + // TODO(jtattermusch): include the following check + //if (Descriptor.MappedType == MappedType.Message && Descriptor.MessageType.Options.MessageSetWireFormat) + //{ + // throw new ArgumentException( + // "option message_set_wire_format = true; is not supported in Lite runtime extensions."); + //} + + AddClsComplianceCheck(writer); + writer->Write("$0$ ", class_access_level()); + writer->WriteLine( + "static pb::$3$<$0$, $1$> $2$;", + extends_, + type_name(), + property_name(), + descriptor_->is_repeated() ? + "GeneratedRepeatExtensionLite" : "GeneratedExtensionLite"); + } else if (descriptor_->is_repeated()) { + AddClsComplianceCheck(writer); + writer->WriteLine( + "$0$ static pb::GeneratedExtensionBase<scg::IList<$1$>> $2$;", + class_access_level(), type_name(), property_name()); + } else { + AddClsComplianceCheck(writer); + writer->WriteLine("$0$ static pb::GeneratedExtensionBase<$1$> $2$;", + class_access_level(), type_name(), property_name()); + } +} + +void ExtensionGenerator::GenerateStaticVariableInitializers(Writer* writer) { + if (use_lite_runtime()) { + writer->WriteLine("$0$.$1$ = ", scope_, property_name()); + writer->Indent(); + writer->WriteLine( + "new pb::$0$<$1$, $2$>(", + descriptor_->is_repeated() ? + "GeneratedRepeatExtensionLite" : "GeneratedExtensionLite", + extends_, type_name()); + writer->Indent(); + writer->WriteLine("\"$0$\",", descriptor_->full_name()); + writer->WriteLine("$0$.DefaultInstance,", extends_); + if (!descriptor_->is_repeated()) { + std::string default_val; + if (descriptor_->has_default_value()) { + default_val = default_value(); + } else { + default_val = is_nullable_type() ? "null" : ("default(" + type_name() + ")"); + } + writer->WriteLine("$0$,", default_val); + } + writer->WriteLine( + "$0$,", + (GetCSharpType(descriptor_->type()) == CSHARPTYPE_MESSAGE) ? + type_name() + ".DefaultInstance" : "null"); + writer->WriteLine( + "$0$,", + (GetCSharpType(descriptor_->type()) == CSHARPTYPE_ENUM) ? + "new EnumLiteMap<" + type_name() + ">()" : "null"); + writer->WriteLine("$0$.$1$FieldNumber,", scope_, + GetPropertyName(descriptor_)); + writer->Write("pbd::FieldType.$0$", capitalized_type_name()); + if (descriptor_->is_repeated()) { + writer->WriteLine(","); + writer->Write(descriptor_->is_packed() ? "true" : "false"); + } + writer->Outdent(); + writer->WriteLine(");"); + writer->Outdent(); + } + else if (descriptor_->is_repeated()) + { + writer->WriteLine( + "$0$.$1$ = pb::GeneratedRepeatExtension<$2$>.CreateInstance($0$.Descriptor.Extensions[$3$]);", + scope_, property_name(), type_name(), SimpleItoa(descriptor_->index())); + } + else + { + writer->WriteLine( + "$0$.$1$ = pb::GeneratedSingleExtension<$2$>.CreateInstance($0$.Descriptor.Extensions[$3$]);", + scope_, property_name(), type_name(), SimpleItoa(descriptor_->index())); + } +} + +void ExtensionGenerator::GenerateExtensionRegistrationCode(Writer* writer) { + writer->WriteLine("registry.Add($0$.$1$);", scope_, property_name()); +} + +void ExtensionGenerator::WriteHash(Writer* writer) { +} + +void ExtensionGenerator::WriteEquals(Writer* writer) { +} + +void ExtensionGenerator::WriteToString(Writer* writer) { +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_extension.h b/src/google/protobuf/compiler/csharp/csharp_extension.h new file mode 100644 index 00000000..203f6e5e --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_extension.h @@ -0,0 +1,80 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_EXTENSION_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_EXTENSION_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class ExtensionGenerator : public FieldGeneratorBase { + public: + ExtensionGenerator(const FieldDescriptor* descriptor); + ~ExtensionGenerator(); + + void GenerateStaticVariableInitializers(Writer* writer); + void GenerateExtensionRegistrationCode(Writer* writer); + void Generate(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + virtual void GenerateMembers(Writer* writer) {}; + virtual void GenerateBuilderMembers(Writer* writer) {}; + virtual void GenerateMergingCode(Writer* writer) {}; + virtual void GenerateBuildingCode(Writer* writer) {}; + virtual void GenerateParsingCode(Writer* writer) {}; + virtual void GenerateSerializationCode(Writer* writer) {}; + virtual void GenerateSerializedSizeCode(Writer* writer) {}; + + private: + std::string scope_; + std::string extends_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_EXTENSION_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc new file mode 100644 index 00000000..ed4d55c4 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -0,0 +1,393 @@ +// 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 <limits> +#include <sstream> + +#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/compiler/csharp/csharp_field_base.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor, + int fieldOrdinal) + : SourceGeneratorBase(descriptor->file()), + descriptor_(descriptor), + fieldOrdinal_(fieldOrdinal) { +} + +FieldGeneratorBase::~FieldGeneratorBase() { +} + +void FieldGeneratorBase::AddDeprecatedFlag(Writer* writer) { + if (descriptor_->options().deprecated()) + { + writer->WriteLine("[global::System.ObsoleteAttribute()]"); + } +} + +void FieldGeneratorBase::AddNullCheck(Writer* writer) { + AddNullCheck(writer, "value"); +} + +void FieldGeneratorBase::AddNullCheck(Writer* writer, const std::string& name) { + if (is_nullable_type()) { + writer->WriteLine(" pb::ThrowHelper.ThrowIfNull($0$, \"$0$\");", name); + } +} + +void FieldGeneratorBase::AddPublicMemberAttributes(Writer* writer) { + AddDeprecatedFlag(writer); + AddClsComplianceCheck(writer); +} + +void FieldGeneratorBase::AddClsComplianceCheck(Writer* writer) { + if (cls_compliance() && !is_cls_compliant()) { + writer->WriteLine("[global::System.CLSCompliant(false)]"); + } +} + +std::string FieldGeneratorBase::property_name() { + return GetPropertyName(descriptor_); +} + +std::string FieldGeneratorBase::name() { + return UnderscoresToCamelCase(GetFieldName(descriptor_), false); +} + +std::string FieldGeneratorBase::type_name() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + return GetClassName(descriptor_->enum_type()); + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return GetClassName(descriptor_->message_type()); + case FieldDescriptor::TYPE_DOUBLE: + return "double"; + case FieldDescriptor::TYPE_FLOAT: + return "float"; + case FieldDescriptor::TYPE_INT64: + return "long"; + case FieldDescriptor::TYPE_UINT64: + return "ulong"; + case FieldDescriptor::TYPE_INT32: + return "int"; + case FieldDescriptor::TYPE_FIXED64: + return "ulong"; + case FieldDescriptor::TYPE_FIXED32: + return "uint"; + case FieldDescriptor::TYPE_BOOL: + return "bool"; + case FieldDescriptor::TYPE_STRING: + return "string"; + case FieldDescriptor::TYPE_BYTES: + return "pb::ByteString"; + case FieldDescriptor::TYPE_UINT32: + return "uint"; + case FieldDescriptor::TYPE_SFIXED32: + return "int"; + case FieldDescriptor::TYPE_SFIXED64: + return "long"; + case FieldDescriptor::TYPE_SINT32: + return "int"; + case FieldDescriptor::TYPE_SINT64: + return "long"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +bool FieldGeneratorBase::has_default_value() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return true; + case FieldDescriptor::TYPE_DOUBLE: + return descriptor_->default_value_double() != 0.0; + case FieldDescriptor::TYPE_FLOAT: + return descriptor_->default_value_float() != 0.0; + case FieldDescriptor::TYPE_INT64: + return descriptor_->default_value_int64() != 0L; + case FieldDescriptor::TYPE_UINT64: + return descriptor_->default_value_uint64() != 0L; + case FieldDescriptor::TYPE_INT32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_FIXED64: + return descriptor_->default_value_uint64() != 0L; + case FieldDescriptor::TYPE_FIXED32: + return descriptor_->default_value_uint32() != 0; + case FieldDescriptor::TYPE_BOOL: + return descriptor_->default_value_bool(); + case FieldDescriptor::TYPE_STRING: + return true; + case FieldDescriptor::TYPE_BYTES: + return true; + case FieldDescriptor::TYPE_UINT32: + return descriptor_->default_value_uint32() != 0; + case FieldDescriptor::TYPE_SFIXED32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_SFIXED64: + return descriptor_->default_value_int64() != 0L; + case FieldDescriptor::TYPE_SINT32: + return descriptor_->default_value_int32() != 0; + case FieldDescriptor::TYPE_SINT64: + return descriptor_->default_value_int64() != 0L; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return true; + } +} + +bool FieldGeneratorBase::is_nullable_type() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + case FieldDescriptor::TYPE_DOUBLE: + case FieldDescriptor::TYPE_FLOAT: + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_BOOL: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_SINT64: + return false; + + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + return true; + + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return true; + } +} + +bool FieldGeneratorBase::is_cls_compliant() { + CSharpType type = GetCSharpType(descriptor_->type()); + return (type != CSHARPTYPE_UINT32) && (type != CSHARPTYPE_UINT64) + && (UnderscoresToPascalCase(name()).substr(0, 1) != "_"); +} + +inline bool IsNaN(double value) { + // NaN is never equal to anything, even itself. + return value != value; +} + +bool AllPrintableAscii(const std::string& text) { + for(int i = 0; i < text.size(); i++) { + if (text[i] < 0x20 || text[i] > 0x7e) { + return false; + } + } + return true; +} + +std::string FieldGeneratorBase::GetStringDefaultValueInternal() { + if (!descriptor_->has_default_value()) { + return "\"\""; + } + if (AllPrintableAscii(descriptor_->default_value_string())) { + // All chars are ASCII and printable. In this case we only + // need to escape quotes and backslashes. + std::string temp = descriptor_->default_value_string(); + temp = StringReplace(temp, "\\", "\\\\", true); + temp = StringReplace(temp, "'", "\\'", true); + temp = StringReplace(temp, "\"", "\\\"", true); + return "\"" + temp + "\""; + } + if (use_lite_runtime()) { + return "pb::ByteString.FromBase64(\"" + + StringToBase64(descriptor_->default_value_string()) + + "\").ToStringUtf8()"; + } + return "(string) " + GetClassName(descriptor_->containing_type()) + + ".Descriptor.Fields[" + SimpleItoa(descriptor_->index()) + + "].DefaultValue"; +} + +std::string FieldGeneratorBase::GetBytesDefaultValueInternal() { + if (!descriptor_->has_default_value()) { + return "pb::ByteString.Empty"; + } + if (use_lite_runtime()) { + return "pb::ByteString.FromBase64(\"" + StringToBase64(descriptor_->default_value_string()) + "\")"; + } + return "(pb::ByteString) "+ GetClassName(descriptor_->containing_type()) + + ".Descriptor.Fields[" + SimpleItoa(descriptor_->index()) + "].DefaultValue"; +} + +std::string FieldGeneratorBase::default_value() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + return type_name() + "." + descriptor_->default_value_enum()->name(); + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + return type_name() + ".DefaultInstance"; + case FieldDescriptor::TYPE_DOUBLE: { + double value = descriptor_->default_value_double(); + if (value == numeric_limits<double>::infinity()) { + return "double.PositiveInfinity"; + } else if (value == -numeric_limits<double>::infinity()) { + return "double.NegativeInfinity"; + } else if (IsNaN(value)) { + return "double.NaN"; + } + return SimpleDtoa(value) + "D"; + } + case FieldDescriptor::TYPE_FLOAT: { + float value = descriptor_->default_value_float(); + if (value == numeric_limits<float>::infinity()) { + return "float.PositiveInfinity"; + } else if (value == -numeric_limits<float>::infinity()) { + return "float.NegativeInfinity"; + } else if (IsNaN(value)) { + return "float.NaN"; + } + return SimpleFtoa(value) + "F"; + } + case FieldDescriptor::TYPE_INT64: + return SimpleItoa(descriptor_->default_value_int64()) + "L"; + case FieldDescriptor::TYPE_UINT64: + return SimpleItoa(descriptor_->default_value_uint64()) + "UL"; + case FieldDescriptor::TYPE_INT32: + return SimpleItoa(descriptor_->default_value_int32()); + case FieldDescriptor::TYPE_FIXED64: + return SimpleItoa(descriptor_->default_value_uint64()) + "UL"; + case FieldDescriptor::TYPE_FIXED32: + return SimpleItoa(descriptor_->default_value_uint32()); + case FieldDescriptor::TYPE_BOOL: + if (descriptor_->default_value_bool()) { + return "true"; + } else { + return "false"; + } + case FieldDescriptor::TYPE_STRING: + return GetStringDefaultValueInternal(); + case FieldDescriptor::TYPE_BYTES: + return GetBytesDefaultValueInternal(); + case FieldDescriptor::TYPE_UINT32: + return SimpleItoa(descriptor_->default_value_uint32()); + case FieldDescriptor::TYPE_SFIXED32: + return SimpleItoa(descriptor_->default_value_int32()); + case FieldDescriptor::TYPE_SFIXED64: + return SimpleItoa(descriptor_->default_value_int64()) + "L"; + case FieldDescriptor::TYPE_SINT32: + return SimpleItoa(descriptor_->default_value_int32()); + case FieldDescriptor::TYPE_SINT64: + return SimpleItoa(descriptor_->default_value_int64()) + "L"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +std::string FieldGeneratorBase::number() { + return SimpleItoa(descriptor_->number()); +} + +std::string FieldGeneratorBase::message_or_group() { + return + (descriptor_->type() == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; +} + +std::string FieldGeneratorBase::capitalized_type_name() { + switch (descriptor_->type()) { + case FieldDescriptor::TYPE_ENUM: + return "Enum"; + case FieldDescriptor::TYPE_MESSAGE: + return "Message"; + case FieldDescriptor::TYPE_GROUP: + return "Group"; + case FieldDescriptor::TYPE_DOUBLE: + return "Double"; + case FieldDescriptor::TYPE_FLOAT: + return "Float"; + case FieldDescriptor::TYPE_INT64: + return "Int64"; + case FieldDescriptor::TYPE_UINT64: + return "UInt64"; + case FieldDescriptor::TYPE_INT32: + return "Int32"; + case FieldDescriptor::TYPE_FIXED64: + return "Fixed64"; + case FieldDescriptor::TYPE_FIXED32: + return "Fixed32"; + case FieldDescriptor::TYPE_BOOL: + return "Bool"; + case FieldDescriptor::TYPE_STRING: + return "String"; + case FieldDescriptor::TYPE_BYTES: + return "Bytes"; + case FieldDescriptor::TYPE_UINT32: + return "UInt32"; + case FieldDescriptor::TYPE_SFIXED32: + return "SFixed32"; + case FieldDescriptor::TYPE_SFIXED64: + return "SFixed64"; + case FieldDescriptor::TYPE_SINT32: + return "SInt32"; + case FieldDescriptor::TYPE_SINT64: + return "SInt64"; + default: + GOOGLE_LOG(FATAL)<< "Unknown field type."; + return ""; + } +} + +std::string FieldGeneratorBase::field_ordinal() { + return SimpleItoa(fieldOrdinal_); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h new file mode 100644 index 00000000..4f3a7658 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -0,0 +1,100 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ + +#include <string> +#include <google/protobuf/stubs/strutil.h> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class FieldGeneratorBase : public SourceGeneratorBase { + public: + FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal); + ~FieldGeneratorBase(); + + virtual void GenerateMembers(Writer* writer) = 0; + virtual void GenerateBuilderMembers(Writer* writer) = 0; + virtual void GenerateMergingCode(Writer* writer) = 0; + virtual void GenerateBuildingCode(Writer* writer) = 0; + virtual void GenerateParsingCode(Writer* writer) = 0; + virtual void GenerateSerializationCode(Writer* writer) = 0; + virtual void GenerateSerializedSizeCode(Writer* writer) = 0; + + virtual void WriteHash(Writer* writer) = 0; + virtual void WriteEquals(Writer* writer) = 0; + virtual void WriteToString(Writer* writer) = 0; + + protected: + const FieldDescriptor* descriptor_; + const int fieldOrdinal_; + + void AddDeprecatedFlag(Writer* writer); + void AddNullCheck(Writer* writer); + void AddNullCheck(Writer* writer, const std::string& name); + + void AddPublicMemberAttributes(Writer* writer); + void AddClsComplianceCheck(Writer* writer); + + std::string property_name(); + std::string name(); + std::string type_name(); + bool has_default_value(); + bool is_nullable_type(); + bool is_cls_compliant(); + std::string default_value(); + std::string number(); + std::string message_or_group(); + std::string capitalized_type_name(); + std::string field_ordinal(); + + private: + std::string GetStringDefaultValueInternal(); + std::string GetBytesDefaultValueInternal(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorBase); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_FIELD_BASE_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc new file mode 100644 index 00000000..61ed37ad --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -0,0 +1,99 @@ +// 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 <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/compiler/csharp/csharp_generator.h> +#include <google/protobuf/compiler/csharp/csharp_umbrella_class.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +using google::protobuf::internal::scoped_ptr; + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +std::string GetOutputFile(const google::protobuf::FileDescriptor* file, const std::string file_extension) +{ + return GetFileUmbrellaClassname(file) + file_extension; +} + +void GenerateFile(const google::protobuf::FileDescriptor* file, + Writer* writer) { + UmbrellaClassGenerator umbrellaGenerator(file); + umbrellaGenerator.Generate(writer); +} + +bool Generator::Generate( + const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const { + + vector<pair<string, string> > options; + ParseGeneratorParameter(parameter, &options); + + std::string file_extension = ".cs"; + for (int i = 0; i < options.size(); i++) { + if (options[i].first == "no_cls_compliance") { + *error = "Turning off CLS compliance is not implemented yet."; + return false; + } else if (options[i].first == "file_extension") { + file_extension = options[i].second; + } else { + *error = "Unknown generator option: " + options[i].first; + return false; + } + } + + std::string filename = GetOutputFile(file, file_extension); + scoped_ptr<io::ZeroCopyOutputStream> output( + generator_context->Open(filename)); + io::Printer printer(output.get(), '$'); + Writer writer(&printer); + + GenerateFile(file, &writer); + + return true; +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.h b/src/google/protobuf/compiler/csharp/csharp_generator.h new file mode 100644 index 00000000..9b54e914 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_generator.h @@ -0,0 +1,58 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class LIBPROTOC_EXPORT Generator + : public google::protobuf::compiler::CodeGenerator { + virtual bool Generate( + const FileDescriptor* file, + const string& parameter, + GeneratorContext* generator_context, + string* error) const; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_GENERATOR_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc new file mode 100644 index 00000000..7ef7df42 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc @@ -0,0 +1,54 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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 <memory> + +#include <google/protobuf/compiler/ruby/ruby_generator.h> +#include <google/protobuf/compiler/command_line_interface.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/io/printer.h> + +#include <google/protobuf/testing/googletest.h> +#include <gtest/gtest.h> +#include <google/protobuf/testing/file.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { +namespace { + +// TODO(jtattermusch): add some tests. + +} // namespace +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc new file mode 100644 index 00000000..4580b7be --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -0,0 +1,409 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <algorithm> +#include <google/protobuf/stubs/hash.h> +#include <limits> +#include <vector> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +#include <google/protobuf/compiler/csharp/csharp_field_base.h> +#include <google/protobuf/compiler/csharp/csharp_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_primitive_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +CSharpType GetCSharpType(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_INT64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_UINT32: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_UINT64: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_SINT32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_SINT64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_FIXED32: + return CSHARPTYPE_UINT32; + case FieldDescriptor::TYPE_FIXED64: + return CSHARPTYPE_UINT64; + case FieldDescriptor::TYPE_SFIXED32: + return CSHARPTYPE_INT32; + case FieldDescriptor::TYPE_SFIXED64: + return CSHARPTYPE_INT64; + case FieldDescriptor::TYPE_FLOAT: + return CSHARPTYPE_FLOAT; + case FieldDescriptor::TYPE_DOUBLE: + return CSHARPTYPE_DOUBLE; + case FieldDescriptor::TYPE_BOOL: + return CSHARPTYPE_BOOL; + case FieldDescriptor::TYPE_ENUM: + return CSHARPTYPE_ENUM; + case FieldDescriptor::TYPE_STRING: + return CSHARPTYPE_STRING; + case FieldDescriptor::TYPE_BYTES: + return CSHARPTYPE_BYTESTRING; + case FieldDescriptor::TYPE_GROUP: + return CSHARPTYPE_MESSAGE; + case FieldDescriptor::TYPE_MESSAGE: + return CSHARPTYPE_MESSAGE; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL)<< "Can't get here."; + return (CSharpType) -1; +} + +std::string StripDotProto(const std::string& proto_file) { + int lastindex = proto_file.find_last_of("."); + return proto_file.substr(0, lastindex); +} + +std::string GetFileNamespace(const FileDescriptor* descriptor) { + if (descriptor->options().has_csharp_namespace()) { + return descriptor->options().csharp_namespace(); + } + return descriptor->package(); +} + +std::string GetUmbrellaClassNameInternal(const std::string& proto_file) { + int lastslash = proto_file.find_last_of("/"); + std::string base = proto_file.substr(lastslash + 1); + return UnderscoresToPascalCase(StripDotProto(base)); +} + +std::string GetFileUmbrellaClassname(const FileDescriptor* descriptor) { + // umbrella_classname can no longer be set using message option. + return GetUmbrellaClassNameInternal(descriptor->name()); +} + +std::string GetFileUmbrellaNamespace(const FileDescriptor* descriptor) { + // TODO(jtattermusch): reintroduce csharp_umbrella_namespace option + bool collision = false; + std::string umbrella_classname = GetFileUmbrellaClassname(descriptor); + for(int i = 0; i < descriptor->message_type_count(); i++) { + if (descriptor->message_type(i)->name() == umbrella_classname) { + collision = true; + break; + } + } + for (int i = 0; i < descriptor->service_count(); i++) { + if (descriptor->service(i)->name() == umbrella_classname) { + collision = true; + break; + } + } + for (int i = 0; i < descriptor->enum_type_count(); i++) { + if (descriptor->enum_type(i)->name() == umbrella_classname) { + collision = true; + break; + } + } + return collision ? "Proto" : ""; +} + +// TODO(jtattermusch): can we reuse a utility function? +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter) { + string result; + // Note: I distrust ctype.h due to locales. + for (int i = 0; i < input.size(); i++) { + if ('a' <= input[i] && input[i] <= 'z') { + if (cap_next_letter) { + result += input[i] + ('A' - 'a'); + } else { + result += input[i]; + } + cap_next_letter = false; + } else if ('A' <= input[i] && input[i] <= 'Z') { + if (i == 0 && !cap_next_letter) { + // Force first letter to lower-case unless explicitly told to + // capitalize it. + result += input[i] + ('a' - 'A'); + } else { + // Capital letters after the first are left as-is. + result += input[i]; + } + cap_next_letter = false; + } else if ('0' <= input[i] && input[i] <= '9') { + result += input[i]; + cap_next_letter = true; + } else { + cap_next_letter = true; + } + } + // Add a trailing "_" if the name should be altered. + if (input[input.size() - 1] == '#') { + result += '_'; + } + return result; +} + +std::string UnderscoresToPascalCase(const std::string& input) { + return UnderscoresToCamelCase(input, true); +} + +std::string ToCSharpName(const std::string& name, const FileDescriptor* file) { + std::string result = GetFileNamespace(file); + if (result != "") { + result += '.'; + } + string classname; + if (file->package().empty()) { + classname = name; + } else { + // Strip the proto package from full_name since we've replaced it with + // the C# namespace. + classname = name.substr(file->package().size() + 1); + } + result += StringReplace(classname, ".", ".Types.", false); + return "global::" + result; +} + + + +std::string GetFullUmbrellaClassName(const FileDescriptor* descriptor) { + std::string result = GetFileNamespace(descriptor); + if (!result.empty()) { + result += '.'; + } + result += GetQualifiedUmbrellaClassName(descriptor); + return "global::" + result; +} + +std::string GetQualifiedUmbrellaClassName(const FileDescriptor* descriptor) { + std::string umbrellaNamespace = GetFileUmbrellaNamespace(descriptor); + std::string umbrellaClassname = GetFileUmbrellaClassname(descriptor); + + std::string fullName = umbrellaClassname; + if (!umbrellaNamespace.empty()) { + fullName = umbrellaNamespace + "." + umbrellaClassname; + } + return fullName; +} + +std::string GetClassName(const Descriptor* descriptor) { + return ToCSharpName(descriptor->full_name(), descriptor->file()); +} + +std::string GetClassName(const EnumDescriptor* descriptor) { + return ToCSharpName(descriptor->full_name(), descriptor->file()); +} + +// Groups are hacky: The name of the field is just the lower-cased name +// of the group type. In C#, though, we would like to retain the original +// capitalization of the type name. +std::string GetFieldName(const FieldDescriptor* descriptor) { + if (descriptor->type() == FieldDescriptor::TYPE_GROUP) { + return descriptor->message_type()->name(); + } else { + return descriptor->name(); + } +} + +std::string GetFieldConstantName(const FieldDescriptor* field) { + return GetPropertyName(field) + "FieldNumber"; +} + +std::string GetPropertyName(const FieldDescriptor* descriptor) { + // TODO(jtattermusch): consider introducing csharp_property_name field option + std::string property_name = UnderscoresToPascalCase(GetFieldName(descriptor)); + if (property_name == descriptor->containing_type()->name()) { + property_name += "_"; + } + return property_name; +} + +// TODO: c&p from Java protoc plugin +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int GetFixedSize(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return -1; + case FieldDescriptor::TYPE_INT64 : return -1; + case FieldDescriptor::TYPE_UINT32 : return -1; + case FieldDescriptor::TYPE_UINT64 : return -1; + case FieldDescriptor::TYPE_SINT32 : return -1; + case FieldDescriptor::TYPE_SINT64 : return -1; + case FieldDescriptor::TYPE_FIXED32 : return internal::WireFormatLite::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64 : return internal::WireFormatLite::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: return internal::WireFormatLite::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: return internal::WireFormatLite::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT : return internal::WireFormatLite::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE : return internal::WireFormatLite::kDoubleSize; + + case FieldDescriptor::TYPE_BOOL : return internal::WireFormatLite::kBoolSize; + case FieldDescriptor::TYPE_ENUM : return -1; + + case FieldDescriptor::TYPE_STRING : return -1; + case FieldDescriptor::TYPE_BYTES : return -1; + case FieldDescriptor::TYPE_GROUP : return -1; + case FieldDescriptor::TYPE_MESSAGE : return -1; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + +static const char base64_chars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +std::string StringToBase64(const std::string& input) { + std::string result; + size_t remaining = input.size(); + const unsigned char *src = (const unsigned char*) input.c_str(); + while (remaining > 2) { + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)]; + result += base64_chars[((src[1] & 0xf) << 2) | (src[2] >> 6)]; + result += base64_chars[src[2] & 0x3f]; + remaining -= 3; + src += 3; + } + switch (remaining) { + case 2: + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4) | (src[1] >> 4)]; + result += base64_chars[(src[1] & 0xf) << 2]; + result += '='; + src += 2; + break; + case 1: + result += base64_chars[src[0] >> 2]; + result += base64_chars[((src[0] & 0x3) << 4)]; + result += '='; + result += '='; + src += 1; + break; + } + return result; +} + +std::string FileDescriptorToBase64(const FileDescriptor* descriptor) { + std::string fdp_bytes; + FileDescriptorProto fdp; + descriptor->CopyTo(&fdp); + fdp.SerializeToString(&fdp_bytes); + return StringToBase64(fdp_bytes); +} + +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal) { + switch (descriptor->type()) { + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + if (descriptor->is_repeated()) { + return new RepeatedMessageFieldGenerator(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); + } + default: + if (descriptor->is_repeated()) { + return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal); + } else { + return new PrimitiveFieldGenerator(descriptor, fieldOrdinal); + } + } +} + +bool HasRequiredFields(const Descriptor* descriptor, std::set<const Descriptor*>* already_seen) { + if (already_seen->find(descriptor) != already_seen->end()) { + // The type is already in cache. This means that either: + // a. The type has no required fields. + // b. We are in the midst of checking if the type has required fields, + // somewhere up the stack. In this case, we know that if the type + // has any required fields, they'll be found when we return to it, + // and the whole call to HasRequiredFields() will return true. + // Therefore, we don't have to check if this type has required fields + // here. + return false; + } + already_seen->insert(descriptor); + + // If the type has extensions, an extension with message type could contain + // required fields, so we have to be conservative and assume such an + // extension exists. + if (descriptor->extension_count() > 0) { + return true; + } + + for (int i = 0; i < descriptor->field_count(); i++) { + const FieldDescriptor* field = descriptor->field(i); + if (field->is_required()) { + return true; + } + if (GetCSharpType(field->type()) == CSHARPTYPE_MESSAGE) { + if (HasRequiredFields(field->message_type(), already_seen)) { + return true; + } + } + } + return false; +} + +bool HasRequiredFields(const Descriptor* descriptor) { + std::set<const Descriptor*> already_seen; + return HasRequiredFields(descriptor, &already_seen); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h new file mode 100644 index 00000000..8fdd214e --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -0,0 +1,108 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ + +#include <string> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class FieldGeneratorBase; + +// TODO: start using this enum. +enum CSharpType { + CSHARPTYPE_INT32 = 1, + CSHARPTYPE_INT64 = 2, + CSHARPTYPE_UINT32 = 3, + CSHARPTYPE_UINT64 = 4, + CSHARPTYPE_FLOAT = 5, + CSHARPTYPE_DOUBLE = 6, + CSHARPTYPE_BOOL = 7, + CSHARPTYPE_STRING = 8, + CSHARPTYPE_BYTESTRING = 9, + CSHARPTYPE_MESSAGE = 10, + CSHARPTYPE_ENUM = 11, + MAX_CSHARPTYPE = 11 +}; + +// Converts field type to corresponding C# type. +CSharpType GetCSharpType(FieldDescriptor::Type type); + +std::string StripDotProto(const std::string& proto_file); + +std::string GetFileNamespace(const FileDescriptor* descriptor); +std::string GetFileUmbrellaClassname(const FileDescriptor* descriptor); +std::string GetFileUmbrellaNamespace(const FileDescriptor* descriptor); + +std::string GetFullUmbrellaClassName(const FileDescriptor* descriptor); + +std::string GetQualifiedUmbrellaClassName(const FileDescriptor* descriptor); + +std::string GetClassName(const Descriptor* descriptor); +std::string GetClassName(const EnumDescriptor* descriptor); + +std::string GetFieldName(const FieldDescriptor* descriptor); + +std::string GetFieldConstantName(const FieldDescriptor* field); + +std::string GetPropertyName(const FieldDescriptor* descriptor); + +int GetFixedSize(FieldDescriptor::Type type); + +std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter); + +std::string UnderscoresToPascalCase(const std::string& input); + +// TODO(jtattermusch): perhaps we could move this to strutil +std::string StringToBase64(const std::string& input); + +std::string FileDescriptorToBase64(const FileDescriptor* descriptor); + +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + +bool HasRequiredFields(const Descriptor* descriptor); + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ 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..f7c8ddfb --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -0,0 +1,897 @@ +// 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); + // TODO(jtattermusch): same code for cls compliance is in csharp_extension + if (cls_compliance() + && GetFieldConstantName(fieldDescriptor)[0] == '_') { + writer->WriteLine("[global::System.CLSCompliant(false)]"); + } + + // 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()) { + 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 diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h new file mode 100644 index 00000000..b8d15df0 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_message.h @@ -0,0 +1,98 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ + +#include <string> +#include <vector> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; +class FieldGeneratorBase; + +class MessageGenerator : public SourceGeneratorBase { + public: + MessageGenerator(const Descriptor* descriptor); + ~MessageGenerator(); + + void GenerateStaticVariables(Writer* printer); + void GenerateStaticVariableInitializers(Writer* printer); + void GenerateExtensionRegistrationCode(Writer* printer); + void Generate(Writer* printer); + + private: + const Descriptor* descriptor_; + std::vector<std::string> field_names_; + std::vector<const FieldDescriptor*> fields_by_number_; + + void GenerateLiteRuntimeMethods(Writer* writer); + void GenerateMessageSerializationMethods(Writer* writer); + void GenerateSerializeOneField(Writer* writer, + const FieldDescriptor* fieldDescriptor); + void GenerateSerializeOneExtensionRange( + Writer* writer, const Descriptor::ExtensionRange* extendsionRange); + void GenerateParseFromMethods(Writer* writer); + void GenerateBuilder(Writer* writer); + void GenerateCommonBuilderMethods(Writer* writer); + void GenerateBuilderParsingMethods(Writer* writer); + void GenerateIsInitialized(Writer* writer); + + int GetFieldOrdinal(const FieldDescriptor* descriptor); + FieldGeneratorBase* CreateFieldGeneratorInternal( + const FieldDescriptor* descriptor); + + std::string class_name(); + std::string full_class_name(); + + // field names sorted alphabetically + const std::vector<std::string>& field_names(); + + // field descriptors sorted by number + const std::vector<const FieldDescriptor*>& fields_by_number(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc new file mode 100644 index 00000000..10464c4b --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -0,0 +1,183 @@ +// 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 <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/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +MessageFieldGenerator::~MessageFieldGenerator() { + +} + +void MessageFieldGenerator::GenerateMembers(Writer* writer) { + writer->WriteLine("private bool has$0$;", property_name()); + writer->WriteLine("private $0$ $1$_;", type_name(), name()); + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return has$0$; }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$_ ?? $1$; }", name(), default_value()); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::GenerateBuilderMembers(Writer* writer) { + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.has$0$; }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$; }", property_name()); + 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.has$0$ = true;", property_name()); + writer->WriteLine(" result.$0$_ = value;", 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.has$0$ = true;", property_name()); + writer->WriteLine(" result.$0$_ = builderForValue.Build();", 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.has$0$ &&", property_name()); + writer->WriteLine(" result.$0$_ != $1$) {", name(), default_value()); + writer->WriteLine( + " result.$0$_ = $1$.CreateBuilder(result.$0$_).MergeFrom(value).BuildPartial();", + name(), type_name()); + writer->WriteLine(" } else {"); + writer->WriteLine(" result.$0$_ = value;", name()); + writer->WriteLine(" }"); + writer->WriteLine(" result.has$0$ = true;", property_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.has$0$ = false;", property_name()); + writer->WriteLine(" result.$0$_ = null;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.Has$0$) {", property_name()); + writer->WriteLine(" Merge$0$(other.$0$);", property_name()); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::GenerateBuildingCode(Writer* writer) { + // Nothing to do for singular fields +} + +void MessageFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("$0$.Builder subBuilder = $0$.CreateBuilder();", + type_name()); + writer->WriteLine("if (result.has$0$) {", property_name()); + 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("$0$ = subBuilder.BuildPartial();", property_name()); +} + +void MessageFieldGenerator::GenerateSerializationCode(Writer* writer) { + writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine(" output.Write$0$($1$, field_names[$3$], $2$);", + message_or_group(), number(), property_name(), + field_ordinal()); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine(" size += pb::CodedOutputStream.Compute$0$Size($1$, $2$);", + message_or_group(), number(), property_name()); + writer->WriteLine("}"); +} + +void MessageFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("if (has$0$) hash ^= $1$_.GetHashCode();", property_name(), + name()); +} +void MessageFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine( + "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;", + property_name(), name()); +} +void MessageFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$2$\", has$0$, $1$_, writer);", + property_name(), name(), GetFieldName(descriptor_)); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h new file mode 100644 index 00000000..48bf8be5 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class MessageFieldGenerator : public FieldGeneratorBase { + public: + MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~MessageFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MESSAGE_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc new file mode 100644 index 00000000..54287b41 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -0,0 +1,148 @@ +// 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 <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/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_primitive_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +PrimitiveFieldGenerator::PrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() { + +} + +void PrimitiveFieldGenerator::GenerateMembers(Writer* writer) { + writer->WriteLine("private bool has$0$;", property_name()); + writer->WriteLine("private $0$ $1$_$2$;", type_name(), name(), + has_default_value() ? " = " + default_value() : ""); + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return has$0$; }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return $0$_; }", name()); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::GenerateBuilderMembers(Writer* writer) { + AddDeprecatedFlag(writer); + writer->WriteLine("public bool Has$0$ {", property_name()); + writer->WriteLine(" get { return result.has$0$; }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ $1$ {", type_name(), property_name()); + writer->WriteLine(" get { return result.$0$; }", property_name()); + 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.has$0$ = true;", property_name()); + writer->WriteLine(" result.$0$_ = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.has$0$ = false;", property_name()); + writer->WriteLine(" result.$0$_ = $1$;", name(), default_value()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.Has$0$) {", property_name()); + writer->WriteLine(" $0$ = other.$0$;", property_name()); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::GenerateBuildingCode(Writer* writer) { + // Nothing to do here for primitive types +} + +void PrimitiveFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("result.has$0$ = input.Read$1$(ref result.$2$_);", + property_name(), capitalized_type_name(), name()); +} + +void PrimitiveFieldGenerator::GenerateSerializationCode(Writer* writer) { + writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine(" output.Write$0$($1$, field_names[$3$], $2$);", + capitalized_type_name(), number(), property_name(), + field_ordinal()); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + writer->WriteLine("if (has$0$) {", property_name()); + writer->WriteLine(" size += pb::CodedOutputStream.Compute$0$Size($1$, $2$);", + capitalized_type_name(), number(), property_name()); + writer->WriteLine("}"); +} + +void PrimitiveFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("if (has$0$) hash ^= $1$_.GetHashCode();", property_name(), + name()); +} +void PrimitiveFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine( + "if (has$0$ != other.has$0$ || (has$0$ && !$1$_.Equals(other.$1$_))) return false;", + property_name(), name()); +} +void PrimitiveFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", has$1$, $2$_, writer);", + descriptor_->name(), property_name(), name()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h new file mode 100644 index 00000000..fb27ab43 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class PrimitiveFieldGenerator : public FieldGeneratorBase { + public: + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~PrimitiveFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_PRIMITIVE_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc new file mode 100644 index 00000000..cc8745ae --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc @@ -0,0 +1,226 @@ +// 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 <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/wire_format.h> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() { + +} + +void RepeatedEnumFieldGenerator::GenerateMembers(Writer* writer) { + if (descriptor_->is_packed() && optimize_speed()) { + writer->WriteLine("private int $0$MemoizedSerializedSize;", name()); + } + writer->WriteLine( + "private pbc::PopsicleList<$0$> $1$_ = new pbc::PopsicleList<$0$>();", + type_name(), name()); + AddDeprecatedFlag(writer); + writer->WriteLine("public scg::IList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return pbc::Lists.AsReadOnly($0$_); }", name()); + writer->WriteLine("}"); + + // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option. + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return $0$_.Count; }", name()); + writer->WriteLine("}"); + + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return $0$_[index];", name()); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::GenerateBuilderMembers(Writer* writer) { + // Note: We can return the original list here, because we make it unmodifiable when we build + // We return it via IPopsicleList so that collection initializers work more pleasantly. + AddDeprecatedFlag(writer); + writer->WriteLine("public pbc::IPopsicleList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return PrepareBuilder().$0$_; }", name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return result.$0$Count; }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return result.Get$0$(index);", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Set$0$(int index, $1$ value) {", + property_name(), type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_[index] = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Add$0$($1$ value) {", property_name(), + type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(value);", name(), type_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine( + "public Builder AddRange$0$(scg::IEnumerable<$1$> values) {", + property_name(), type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(values);", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Clear();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.$0$_.Count != 0) {", name()); + writer->WriteLine(" result.$0$_.Add(other.$0$_);", name()); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::GenerateBuildingCode(Writer* writer) { + writer->WriteLine("$0$_.MakeReadOnly();", name()); +} + +void RepeatedEnumFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("scg::ICollection<object> unknownItems;"); + writer->WriteLine( + "input.ReadEnumArray<$0$>(tag, field_name, result.$1$_, out unknownItems);", + type_name(), name()); + if (!use_lite_runtime()) { + writer->WriteLine("if (unknownItems != null) {"); + writer->WriteLine(" if (unknownFields == null) {"); + writer->WriteLine( + " unknownFields = pb::UnknownFieldSet.CreateBuilder(this.UnknownFields);"); + writer->WriteLine(" }"); + writer->WriteLine(" foreach (object rawValue in unknownItems)"); + writer->WriteLine(" if (rawValue is int)"); + writer->WriteLine( + " unknownFields.MergeVarintField($0$, (ulong)(int)rawValue);", + number()); + writer->WriteLine("}"); + } +} + +void RepeatedEnumFieldGenerator::GenerateSerializationCode(Writer* writer) { + writer->WriteLine("if ($0$_.Count > 0) {", name()); + writer->Indent(); + if (descriptor_->is_packed()) { + writer->WriteLine( + "output.WritePackedEnumArray($0$, field_names[$2$], $1$MemoizedSerializedSize, $1$_);", + number(), name(), field_ordinal()); + } else { + writer->WriteLine("output.WriteEnumArray($0$, field_names[$2$], $1$_);", + number(), name(), field_ordinal()); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + writer->WriteLine("{"); + writer->Indent(); + writer->WriteLine("int dataSize = 0;"); + writer->WriteLine("if ($0$_.Count > 0) {", name()); + writer->Indent(); + writer->WriteLine("foreach ($0$ element in $1$_) {", type_name(), name()); + writer->WriteLine( + " dataSize += pb::CodedOutputStream.ComputeEnumSizeNoTag((int) element);"); + writer->WriteLine("}"); + writer->WriteLine("size += dataSize;"); + int tagSize = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type()); + if (descriptor_->is_packed()) { + writer->WriteLine("size += $0$;", SimpleItoa(tagSize)); + writer->WriteLine( + "size += pb::CodedOutputStream.ComputeRawVarint32Size((uint) dataSize);"); + } else { + writer->WriteLine("size += $0$ * $1$_.Count;", SimpleItoa(tagSize), name()); + } + writer->Outdent(); + writer->WriteLine("}"); + // cache the data size for packed fields. + if (descriptor_->is_packed()) { + writer->WriteLine("$0$MemoizedSerializedSize = dataSize;", name()); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedEnumFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("foreach($0$ i in $1$_)", type_name(), name()); + writer->WriteLine(" hash ^= i.GetHashCode();"); +} + +void RepeatedEnumFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if($0$_.Count != other.$0$_.Count) return false;", name()); + writer->WriteLine("for(int ix=0; ix < $0$_.Count; ix++)", name()); + writer->WriteLine(" if(!$0$_[ix].Equals(other.$0$_[ix])) return false;", + name()); +} + +void RepeatedEnumFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", descriptor_->name(), + name()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h new file mode 100644 index 00000000..c872131c --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class RepeatedEnumFieldGenerator : public FieldGeneratorBase { + public: + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~RepeatedEnumFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_ENUM_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc new file mode 100644 index 00000000..2dfcd402 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc @@ -0,0 +1,201 @@ +// 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 <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/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() { + +} + +void RepeatedMessageFieldGenerator::GenerateMembers(Writer* writer) { + writer->WriteLine( + "private pbc::PopsicleList<$0$> $1$_ = new pbc::PopsicleList<$0$>();", + type_name(), name()); + AddDeprecatedFlag(writer); + writer->WriteLine("public scg::IList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return $0$_; }", name()); + writer->WriteLine("}"); + + // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option. + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return $0$_.Count; }", name()); + writer->WriteLine("}"); + + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return $0$_[index];", name()); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::GenerateBuilderMembers(Writer* writer) { + // Note: We can return the original list here, because we make it unmodifiable when we build + // We return it via IPopsicleList so that collection initializers work more pleasantly. + AddDeprecatedFlag(writer); + writer->WriteLine("public pbc::IPopsicleList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return PrepareBuilder().$0$_; }", name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return result.$0$Count; }", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return result.Get$0$(index);", property_name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Set$0$(int index, $1$ value) {", + property_name(), type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_[index] = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + // Extra overload for builder (just on messages) + AddDeprecatedFlag(writer); + writer->WriteLine( + "public Builder Set$0$(int index, $1$.Builder builderForValue) {", + property_name(), type_name()); + AddNullCheck(writer, "builderForValue"); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_[index] = builderForValue.Build();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Add$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(value);", name(), type_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + // Extra overload for builder (just on messages) + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Add$0$($1$.Builder builderForValue) {", + property_name(), type_name()); + AddNullCheck(writer, "builderForValue"); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(builderForValue.Build());", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine( + "public Builder AddRange$0$(scg::IEnumerable<$1$> values) {", + property_name(), type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(values);", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Clear();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.$0$_.Count != 0) {", name()); + writer->WriteLine(" result.$0$_.Add(other.$0$_);", name()); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::GenerateBuildingCode(Writer* writer) { + writer->WriteLine("$0$_.MakeReadOnly();", name()); +} + +void RepeatedMessageFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine( + "input.Read$0$Array(tag, field_name, result.$1$_, $2$.DefaultInstance, extensionRegistry);", + message_or_group(), name(), type_name()); +} + +void RepeatedMessageFieldGenerator::GenerateSerializationCode(Writer* writer) { + writer->WriteLine("if ($0$_.Count > 0) {", name()); + writer->Indent(); + writer->WriteLine("output.Write$0$Array($1$, field_names[$3$], $2$_);", + message_or_group(), number(), name(), field_ordinal()); + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::GenerateSerializedSizeCode(Writer* writer) { + writer->WriteLine("foreach ($0$ element in $1$List) {", type_name(), + property_name()); + writer->WriteLine( + " size += pb::CodedOutputStream.Compute$0$Size($1$, element);", + message_or_group(), number()); + writer->WriteLine("}"); +} + +void RepeatedMessageFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("foreach($0$ i in $1$_)", type_name(), name()); + writer->WriteLine(" hash ^= i.GetHashCode();"); +} +void RepeatedMessageFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if($0$_.Count != other.$0$_.Count) return false;", name()); + writer->WriteLine("for(int ix=0; ix < $0$_.Count; ix++)", name()); + writer->WriteLine(" if(!$0$_[ix].Equals(other.$0$_[ix])) return false;", + name()); +} +void RepeatedMessageFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", + GetFieldName(descriptor_), name()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h new file mode 100644 index 00000000..104274cb --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class RepeatedMessageFieldGenerator : public FieldGeneratorBase { + public: + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~RepeatedMessageFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_MESSAGE_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc new file mode 100644 index 00000000..8b285468 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc @@ -0,0 +1,219 @@ +// 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 <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/wire_format.h> + +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal) + : FieldGeneratorBase(descriptor, fieldOrdinal) { +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() { + +} + +void RepeatedPrimitiveFieldGenerator::GenerateMembers(Writer* writer) { + if (descriptor_->is_packed() && optimize_speed()) { + writer->WriteLine("private int $0$MemoizedSerializedSize;", name()); + } + writer->WriteLine( + "private pbc::PopsicleList<$0$> $1$_ = new pbc::PopsicleList<$0$>();", + type_name(), name()); + AddPublicMemberAttributes(writer); + writer->WriteLine("public scg::IList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return pbc::Lists.AsReadOnly($0$_); }", name()); + writer->WriteLine("}"); + + // TODO(jonskeet): Redundant API calls? Possibly - include for portability though. Maybe create an option. + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return $0$_.Count; }", name()); + writer->WriteLine("}"); + + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return $0$_[index];", name()); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateBuilderMembers(Writer* writer) { + // Note: We can return the original list here, because we make it unmodifiable when we build + // We return it via IPopsicleList so that collection initializers work more pleasantly. + AddPublicMemberAttributes(writer); + writer->WriteLine("public pbc::IPopsicleList<$0$> $1$List {", type_name(), + property_name()); + writer->WriteLine(" get { return PrepareBuilder().$0$_; }", name()); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public int $0$Count {", property_name()); + writer->WriteLine(" get { return result.$0$Count; }", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public $0$ Get$1$(int index) {", type_name(), + property_name()); + writer->WriteLine(" return result.Get$0$(index);", property_name()); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public Builder Set$0$(int index, $1$ value) {", + property_name(), type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_[index] = value;", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine("public Builder Add$0$($1$ value) {", property_name(), + type_name()); + AddNullCheck(writer); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(value);", name(), type_name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddPublicMemberAttributes(writer); + writer->WriteLine( + "public Builder AddRange$0$(scg::IEnumerable<$1$> values) {", + property_name(), type_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Add(values);", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); + AddDeprecatedFlag(writer); + writer->WriteLine("public Builder Clear$0$() {", property_name()); + writer->WriteLine(" PrepareBuilder();"); + writer->WriteLine(" result.$0$_.Clear();", name()); + writer->WriteLine(" return this;"); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateMergingCode(Writer* writer) { + writer->WriteLine("if (other.$0$_.Count != 0) {", name()); + writer->WriteLine(" result.$0$_.Add(other.$0$_);", name()); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateBuildingCode(Writer* writer) { + writer->WriteLine("$0$_.MakeReadOnly();", name()); +} + +void RepeatedPrimitiveFieldGenerator::GenerateParsingCode(Writer* writer) { + writer->WriteLine("input.Read$0$Array(tag, field_name, result.$1$_);", + capitalized_type_name(), name()); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSerializationCode( + Writer* writer) { + writer->WriteLine("if ($0$_.Count > 0) {", name()); + writer->Indent(); + if (descriptor_->is_packed()) { + writer->WriteLine( + "output.WritePacked$0$Array($1$, field_names[$3$], $2$MemoizedSerializedSize, $2$_);", + capitalized_type_name(), number(), name(), field_ordinal()); + } else { + writer->WriteLine("output.Write$0$Array($1$, field_names[$3$], $2$_);", + capitalized_type_name(), number(), name(), + field_ordinal()); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::GenerateSerializedSizeCode( + Writer* writer) { + writer->WriteLine("{"); + writer->Indent(); + writer->WriteLine("int dataSize = 0;"); + int fixedSize = GetFixedSize(descriptor_->type()); + if (fixedSize == -1) { + writer->WriteLine("foreach ($0$ element in $1$List) {", type_name(), + property_name()); + writer->WriteLine( + " dataSize += pb::CodedOutputStream.Compute$0$SizeNoTag(element);", + capitalized_type_name(), number()); + writer->WriteLine("}"); + } else { + writer->WriteLine("dataSize = $0$ * $1$_.Count;", SimpleItoa(fixedSize), name()); + } + writer->WriteLine("size += dataSize;"); + int tagSize = internal::WireFormat::TagSize(descriptor_->number(), descriptor_->type()); + if (descriptor_->is_packed()) { + writer->WriteLine("if ($0$_.Count != 0) {", name()); + writer->WriteLine( + " size += $0$ + pb::CodedOutputStream.ComputeInt32SizeNoTag(dataSize);", + SimpleItoa(tagSize)); + writer->WriteLine("}"); + } else { + writer->WriteLine("size += $0$ * $1$_.Count;", SimpleItoa(tagSize), name()); + } + // cache the data size for packed fields. + if (descriptor_->is_packed()) { + writer->WriteLine("$0$MemoizedSerializedSize = dataSize;", name()); + } + writer->Outdent(); + writer->WriteLine("}"); +} + +void RepeatedPrimitiveFieldGenerator::WriteHash(Writer* writer) { + writer->WriteLine("foreach($0$ i in $1$_)", type_name(), name()); + writer->WriteLine(" hash ^= i.GetHashCode();"); +} +void RepeatedPrimitiveFieldGenerator::WriteEquals(Writer* writer) { + writer->WriteLine("if($0$_.Count != other.$0$_.Count) return false;", name()); + writer->WriteLine("for(int ix=0; ix < $0$_.Count; ix++)", name()); + writer->WriteLine(" if(!$0$_[ix].Equals(other.$0$_[ix])) return false;", + name()); +} +void RepeatedPrimitiveFieldGenerator::WriteToString(Writer* writer) { + writer->WriteLine("PrintField(\"$0$\", $1$_, writer);", descriptor_->name(), + name()); +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h new file mode 100644 index 00000000..07b12015 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_field_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase { + public: + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + ~RepeatedPrimitiveFieldGenerator(); + + virtual void GenerateMembers(Writer* writer); + virtual void GenerateBuilderMembers(Writer* writer); + virtual void GenerateMergingCode(Writer* writer); + virtual void GenerateBuildingCode(Writer* writer); + virtual void GenerateParsingCode(Writer* writer); + virtual void GenerateSerializationCode(Writer* writer); + virtual void GenerateSerializedSizeCode(Writer* writer); + + virtual void WriteHash(Writer* writer); + virtual void WriteEquals(Writer* writer); + virtual void WriteToString(Writer* writer); + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_REPEATED_PRIMITIVE_FIELD_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc new file mode 100644 index 00000000..e39911ee --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc @@ -0,0 +1,80 @@ +// 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 <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/compiler/csharp/csharp_source_generator_base.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor) + : descriptor_(descriptor) { + optimizeSize_ = (descriptor->options().optimize_for() + == FileOptions::CODE_SIZE); + optimizeSpeed_ = (descriptor->options().optimize_for() == FileOptions::SPEED); + useLiteRuntime_ = (descriptor->options().optimize_for() + == FileOptions::LITE_RUNTIME); + + optimizeSpeed_ |= useLiteRuntime_; + runtimeSuffix_ = useLiteRuntime_ ? "Lite" : ""; +} + +SourceGeneratorBase::~SourceGeneratorBase() { +} + +void SourceGeneratorBase::WriteGeneratedCodeAttributes(Writer* writer) { + // This hook can be used to reintroduce generated code attributes in the future. +} + +std::string SourceGeneratorBase::class_access_level() { + return "public"; // public_classes is always on. +} + +bool SourceGeneratorBase::cls_compliance() { + // TODO(jtattermusch): implement this based on "cls_compliance" cmdline param. + return true; +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h new file mode 100644 index 00000000..dbc65d04 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h @@ -0,0 +1,84 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class SourceGeneratorBase { + protected: + SourceGeneratorBase(const FileDescriptor* descriptor); + virtual ~SourceGeneratorBase(); + + std::string class_access_level(); + bool cls_compliance(); + + bool optimize_size() { + return optimizeSize_; + } + bool optimize_speed() { + return optimizeSpeed_; + } + bool use_lite_runtime() { + return useLiteRuntime_; + } + std::string runtime_suffix() { + return runtimeSuffix_; + } + + void WriteGeneratedCodeAttributes(Writer* writer); + + private: + const FileDescriptor* descriptor_; + bool optimizeSize_; + bool optimizeSpeed_; + bool useLiteRuntime_; + std::string runtimeSuffix_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceGeneratorBase); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_SOURCE_GENERATOR_BASE_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc new file mode 100644 index 00000000..358cfa4f --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc @@ -0,0 +1,286 @@ +// 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 <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/compiler/csharp/csharp_umbrella_class.h> +#include <google/protobuf/compiler/csharp/csharp_enum.h> +#include <google/protobuf/compiler/csharp/csharp_extension.h> +#include <google/protobuf/compiler/csharp/csharp_helpers.h> +#include <google/protobuf/compiler/csharp/csharp_message.h> +#include <google/protobuf/compiler/csharp/csharp_writer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +UmbrellaClassGenerator::UmbrellaClassGenerator(const FileDescriptor* file) + : SourceGeneratorBase(file), + file_(file) { + namespace_ = GetFileNamespace(file); + umbrellaClassname_ = GetFileUmbrellaClassname(file); + umbrellaNamespace_ = GetFileUmbrellaNamespace(file); +} + +UmbrellaClassGenerator::~UmbrellaClassGenerator() { +} + +void UmbrellaClassGenerator::Generate(Writer* writer) { + WriteIntroduction(writer); + WriteExtensionRegistration(writer); + + // write children: Extensions + if (file_->extension_count() > 0) { + writer->WriteLine("#region Extensions"); + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(file_->extension(i)); + extensionGenerator.Generate(writer); + } + writer->WriteLine("#endregion"); + writer->WriteLine(); + } + + writer->WriteLine("#region Static variables"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateStaticVariables(writer); + } + writer->WriteLine("#endregion"); + if (!use_lite_runtime()) { + WriteDescriptor(writer); + } else { + WriteLiteExtensions(writer); + } + // Close the class declaration. + writer->Outdent(); + writer->WriteLine("}"); + + // Close the namespace around the umbrella class if defined + if (!umbrellaNamespace_.empty()) { + writer->Outdent(); + writer->WriteLine("}"); + } + + // write children: Enums + if (file_->enum_type_count() > 0) { + writer->WriteLine("#region Enums"); + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator enumGenerator(file_->enum_type(i)); + enumGenerator.Generate(writer); + } + writer->WriteLine("#endregion"); + writer->WriteLine(); + } + + // write children: Messages + if (file_->message_type_count() > 0) { + writer->WriteLine("#region Messages"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.Generate(writer); + } + writer->WriteLine("#endregion"); + writer->WriteLine(); + } + + // TODO(jtattermusch): add insertion point for services. + + if (!namespace_.empty()) { + writer->Outdent(); + writer->WriteLine("}"); + } + writer->WriteLine(); + writer->WriteLine("#endregion Designer generated code"); +} + +void UmbrellaClassGenerator::WriteIntroduction(Writer* writer) { + writer->WriteLine( + "// Generated by the protocol buffer compiler. DO NOT EDIT!"); + writer->WriteLine("// source: $0$", file_->name()); + writer->WriteLine("#pragma warning disable 1591, 0612, 3021"); + writer->WriteLine("#region Designer generated code"); + + writer->WriteLine(); + writer->WriteLine("using pb = global::Google.ProtocolBuffers;"); + writer->WriteLine("using pbc = global::Google.ProtocolBuffers.Collections;"); + writer->WriteLine("using pbd = global::Google.ProtocolBuffers.Descriptors;"); + writer->WriteLine("using scg = global::System.Collections.Generic;"); + + if (!namespace_.empty()) { + writer->WriteLine("namespace $0$ {", namespace_); + writer->Indent(); + writer->WriteLine(); + } + + // Add the namespace around the umbrella class if defined + if (!umbrellaNamespace_.empty()) { + writer->WriteLine("namespace $0$ {", umbrellaNamespace_); + writer->Indent(); + writer->WriteLine(); + } + + writer->WriteLine( + "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]"); + WriteGeneratedCodeAttributes(writer); + writer->WriteLine("$0$ static partial class $1$ {", class_access_level(), + umbrellaClassname_); + writer->WriteLine(); + writer->Indent(); +} + +void UmbrellaClassGenerator::WriteExtensionRegistration(Writer* writer) { + writer->WriteLine("#region Extension registration"); + writer->WriteLine( + "public static void RegisterAllExtensions(pb::ExtensionRegistry registry) {"); + writer->Indent(); + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(file_->extension(i)); + extensionGenerator.GenerateExtensionRegistrationCode(writer); + } + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateExtensionRegistrationCode(writer); + } + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("#endregion"); +} + +void UmbrellaClassGenerator::WriteDescriptor(Writer* writer) { + writer->WriteLine("#region Descriptor"); + + writer->WriteLine("public static pbd::FileDescriptor Descriptor {"); + writer->WriteLine(" get { return descriptor; }"); + writer->WriteLine("}"); + writer->WriteLine("private static pbd::FileDescriptor descriptor;"); + writer->WriteLine(); + writer->WriteLine("static $0$() {", umbrellaClassname_); + writer->Indent(); + writer->WriteLine( + "byte[] descriptorData = global::System.Convert.FromBase64String("); + writer->Indent(); + writer->Indent(); + writer->WriteLine("string.Concat("); + writer->Indent(); + + // TODO(jonskeet): Consider a C#-escaping format here instead of just Base64. + std::string base64 = FileDescriptorToBase64(file_); + while (base64.size() > 60) { + writer->WriteLine("\"$0$\", ", base64.substr(0, 60)); + base64 = base64.substr(60); + } + writer->Outdent(); + writer->WriteLine("\"$0$\"));", base64); + writer->Outdent(); + writer->Outdent(); + writer->WriteLine( + "pbd::FileDescriptor.InternalDescriptorAssigner assigner = delegate(pbd::FileDescriptor root) {"); + writer->Indent(); + writer->WriteLine("descriptor = root;"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateStaticVariableInitializers(writer); + } + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(file_->extension(i)); + extensionGenerator.GenerateStaticVariableInitializers(writer); + } + + if (uses_extensions()) { + // Must construct an ExtensionRegistry containing all possible extensions + // and return it. + writer->WriteLine( + "pb::ExtensionRegistry registry = pb::ExtensionRegistry.CreateInstance();"); + writer->WriteLine("RegisterAllExtensions(registry);"); + for (int i = 0; i < file_->dependency_count(); i++) { + writer->WriteLine("$0$.RegisterAllExtensions(registry);", + GetFullUmbrellaClassName(file_->dependency(i))); + } + writer->WriteLine("return registry;"); + } else { + writer->WriteLine("return null;"); + } + writer->Outdent(); + writer->WriteLine("};"); + + // ----------------------------------------------------------------- + // Invoke internalBuildGeneratedFileFrom() to build the file. + writer->WriteLine( + "pbd::FileDescriptor.InternalBuildGeneratedFileFrom(descriptorData,"); + writer->WriteLine(" new pbd::FileDescriptor[] {"); + for (int i = 0; i < file_->dependency_count(); i++) { + writer->WriteLine(" $0$.Descriptor, ", + GetFullUmbrellaClassName(file_->dependency(i))); + } + writer->WriteLine(" }, assigner);"); + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("#endregion"); + writer->WriteLine(); +} + +void UmbrellaClassGenerator::WriteLiteExtensions(Writer* writer) { + writer->WriteLine("#region Extensions"); + writer->WriteLine("internal static readonly object Descriptor;"); + writer->WriteLine("static $0$() {", umbrellaClassname_); + writer->Indent(); + writer->WriteLine("Descriptor = null;"); + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator messageGenerator(file_->message_type(i)); + messageGenerator.GenerateStaticVariableInitializers(writer); + } + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator extensionGenerator(file_->extension(i)); + extensionGenerator.GenerateStaticVariableInitializers(writer); + } + writer->Outdent(); + writer->WriteLine("}"); + writer->WriteLine("#endregion"); + writer->WriteLine(); +} + +bool UmbrellaClassGenerator::uses_extensions() { + // TODO(jtattermusch): implement recursive descent that looks for extensions. + // For now, we conservatively assume that extensions are used. + return true; +} + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h new file mode 100644 index 00000000..757f8f91 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_umbrella_class.h @@ -0,0 +1,76 @@ +// 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. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ + +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/csharp/csharp_source_generator_base.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +class Writer; + +class UmbrellaClassGenerator : public SourceGeneratorBase { + public: + UmbrellaClassGenerator(const FileDescriptor* file); + ~UmbrellaClassGenerator(); + + void Generate(Writer* write); + + private: + const FileDescriptor* file_; + + std::string namespace_; + std::string umbrellaClassname_; + std::string umbrellaNamespace_; + + void WriteIntroduction(Writer* writer); + void WriteExtensionRegistration(Writer* writer); + void WriteDescriptor(Writer* writer); + void WriteLiteExtensions(Writer* write); + + bool uses_extensions(); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UmbrellaClassGenerator); +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_UMBRELLA_CLASS_H__ + diff --git a/src/google/protobuf/compiler/csharp/csharp_writer.cc b/src/google/protobuf/compiler/csharp/csharp_writer.cc new file mode 100644 index 00000000..2bcafde5 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_writer.cc @@ -0,0 +1,136 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <algorithm> +#include <google/protobuf/stubs/hash.h> +#include <limits> +#include <vector> + +#include <google/protobuf/compiler/csharp/csharp_writer.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +#include <google/protobuf/compiler/csharp/csharp_field_base.h> +#include <google/protobuf/compiler/csharp/csharp_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_primitive_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h> +#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +Writer::Writer(google::protobuf::io::Printer* printer) + : printer_(printer), + newline_("\n") { + // TODO(jtattermusch): make newline customizable. +} + +Writer::~Writer() { +} + +void Writer::Indent() { + printer_->Indent(); +} + +void Writer::Outdent() { + printer_->Outdent(); +} + +void Writer::Write(const char* text) { + printer_->Print(text); +} + +void Writer::Write(const char* text, const string& value0) { + printer_->Print(text, "0", value0); +} + +void Writer::Write(const char* text, const string& value0, + const string& value1) { + printer_->Print(text, "0", value0, "1", value1); +} + +void Writer::Write(const char* text, const string& value0, const string& value1, + const string& value2) { + printer_->Print(text, "0", value0, "1", value1, "2", value2); +} + +void Writer::Write(const char* text, const string& value0, const string& value1, + const string& value2, const string& value3) { + printer_->Print(text, "0", value0, "1", value1, "2", value2, "3", value3); +} + +void Writer::WriteLine() { + printer_->Print(newline_); +} + +void Writer::WriteLine(const char* text) { + Write(text); + WriteLine(); +} + +void Writer::WriteLine(const char* text, const string& value0) { + Write(text, value0); + WriteLine(); +} + +void Writer::WriteLine(const char* text, const string& value0, + const string& value1) { + Write(text, value0, value1); + WriteLine(); +} + +void Writer::WriteLine(const char* text, const string& value0, + const string& value1, const string& value2) { + Write(text, value0, value1, value2); + WriteLine(); +} + +void Writer::WriteLine(const char* text, const string& value0, + const string& value1, const string& value2, + const string& value3) { + Write(text, value0, value1, value2, value3); + WriteLine(); +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/csharp/csharp_writer.h b/src/google/protobuf/compiler/csharp/csharp_writer.h new file mode 100644 index 00000000..26c59b31 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_writer.h @@ -0,0 +1,93 @@ +// 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. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_WRITER_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_WRITER_H__ + +#include <string> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +// Simple wrapper around Printer that supports customizable line endings +// and number-based variables (e.g. $0$). +class Writer { + public: + Writer(io::Printer* printer); + ~Writer(); + + void Indent(); + void Outdent(); + + void Write(const char* text); + + void Write(const char* text, const string& value0); + + void Write(const char* text, const string& value0, const string& value1); + + void Write(const char* text, const string& value0, const string& value1, + const string& value2); + + void Write(const char* text, const string& value0, const string& value1, + const string& value2, const string& value3); + + void WriteLine(); + + void WriteLine(const char* text); + + void WriteLine(const char* text, const string& value0); + + void WriteLine(const char* text, const string& value0, const string& value1); + + void WriteLine(const char* text, const string& value0, const string& value1, + const string& value2); + + void WriteLine(const char* text, const string& value0, const string& value1, + const string& value2, const string& value3); + private: + io::Printer* printer_; + const char* newline_; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_WRITER_H__ diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 931b8fa3..bc2da38e 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -36,6 +36,7 @@ #include <google/protobuf/compiler/java/java_generator.h> #include <google/protobuf/compiler/javanano/javanano_generator.h> #include <google/protobuf/compiler/ruby/ruby_generator.h> +#include <google/protobuf/compiler/csharp/csharp_generator.h> int main(int argc, char* argv[]) { @@ -68,5 +69,10 @@ int main(int argc, char* argv[]) { cli.RegisterGenerator("--ruby_out", &rb_generator, "Generate Ruby source file."); + // CSharp + google::protobuf::compiler::csharp::Generator csharp_generator; + cli.RegisterGenerator("--csharp_out", &csharp_generator, + "Generate C# source file."); + return cli.Run(argc, argv); } diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 9556206c..9e703d96 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -289,7 +289,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_), -1); FileOptions_descriptor_ = file->message_type(9); - static const int FileOptions_offsets_[14] = { + static const int FileOptions_offsets_[15] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_), @@ -303,6 +303,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, deprecated_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_enable_arenas_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, objc_class_prefix_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, csharp_namespace_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_), }; FileOptions_reflection_ = @@ -663,7 +664,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "t_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.p" "rotobuf.MethodOptions\022\037\n\020client_streamin" "g\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010" - ":\005false\"\347\004\n\013FileOptions\022\024\n\014java_package\030" + ":\005false\"\201\005\n\013FileOptions\022\024\n\014java_package\030" "\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023j" "ava_multiple_files\030\n \001(\010:\005false\022,\n\035java_" "generate_equals_and_hash\030\024 \001(\010:\005false\022%\n" @@ -675,50 +676,51 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "se\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031" "\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_a" "renas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030" - "$ \001(\t\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.g" - "oogle.protobuf.UninterpretedOption\":\n\014Op" - "timizeMode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014" - "LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOpt" - "ions\022&\n\027message_set_wire_format\030\001 \001(\010:\005f" - "alse\022.\n\037no_standard_descriptor_accessor\030" - "\002 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022" - "\021\n\tmap_entry\030\007 \001(\010\022C\n\024uninterpreted_opti" - "on\030\347\007 \003(\0132$.google.protobuf.Uninterprete" - "dOption*\t\010\350\007\020\200\200\200\200\002\"\240\002\n\014FieldOptions\022:\n\005c" - "type\030\001 \001(\0162#.google.protobuf.FieldOption" - "s.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030" - "\005 \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022" - "\023\n\004weak\030\n \001(\010:\005false\022C\n\024uninterpreted_op" - "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" - "tedOption\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001" - "\022\020\n\014STRING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOp" - "tions\022\023\n\013allow_alias\030\002 \001(\010\022\031\n\ndeprecated" - "\030\003 \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007" - " \003(\0132$.google.protobuf.UninterpretedOpti" - "on*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndep" - "recated\030\001 \001(\010:\005false\022C\n\024uninterpreted_op" - "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" - "tedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031" - "\n\ndeprecated\030! \001(\010:\005false\022C\n\024uninterpret" - "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint" - "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptio" - "ns\022\031\n\ndeprecated\030! \001(\010:\005false\022C\n\024uninter" - "preted_option\030\347\007 \003(\0132$.google.protobuf.U" - "ninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023Uninte" - "rpretedOption\022;\n\004name\030\002 \003(\0132-.google.pro" - "tobuf.UninterpretedOption.NamePart\022\030\n\020id" - "entifier_value\030\003 \001(\t\022\032\n\022positive_int_val" - "ue\030\004 \001(\004\022\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014" - "double_value\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014" - "\022\027\n\017aggregate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n" - "\tname_part\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325" - "\001\n\016SourceCodeInfo\022:\n\010location\030\001 \003(\0132(.go" - "ogle.protobuf.SourceCodeInfo.Location\032\206\001" - "\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003" - "(\005B\002\020\001\022\030\n\020leading_comments\030\003 \001(\t\022\031\n\021trai" - "ling_comments\030\004 \001(\t\022!\n\031leading_detached_" - "comments\030\006 \003(\tB)\n\023com.google.protobufB\020D" - "escriptorProtosH\001", 4617); + "$ \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C\n\024unint" + "erpreted_option\030\347\007 \003(\0132$.google.protobuf" + ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005" + "SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003" + "*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027messag" + "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta" + "ndard_descriptor_accessor\030\002 \001(\010:\005false\022\031" + "\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007" + " \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go" + "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200" + "\200\200\200\002\"\240\002\n\014FieldOptions\022:\n\005ctype\030\001 \001(\0162#.g" + "oogle.protobuf.FieldOptions.CType:\006STRIN" + "G\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030\005 \001(\010:\005false\022\031" + "\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:" + "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." + "google.protobuf.UninterpretedOption\"/\n\005C" + "Type\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIE" + "CE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow" + "_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022" + "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google." + "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"" + "}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010:" + "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." + "google.protobuf.UninterpretedOption*\t\010\350\007" + "\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030!" + " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003" + "(\0132$.google.protobuf.UninterpretedOption" + "*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndeprecat" + "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030" + "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" + "tion*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOption\022" + ";\n\004name\030\002 \003(\0132-.google.protobuf.Uninterp" + "retedOption.NamePart\022\030\n\020identifier_value" + "\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022ne" + "gative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006" + " \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggregate_" + "value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part\030\001 \002" + "(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceCodeI" + "nfo\022:\n\010location\030\001 \003(\0132(.google.protobuf." + "SourceCodeInfo.Location\032\206\001\n\010Location\022\020\n\004" + "path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020lead" + "ing_comments\030\003 \001(\t\022\031\n\021trailing_comments\030" + "\004 \001(\t\022!\n\031leading_detached_comments\030\006 \003(\t" + "B)\n\023com.google.protobufB\020DescriptorProto" + "sH\001", 4643); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -7016,6 +7018,7 @@ const int FileOptions::kPyGenericServicesFieldNumber; const int FileOptions::kDeprecatedFieldNumber; const int FileOptions::kCcEnableArenasFieldNumber; const int FileOptions::kObjcClassPrefixFieldNumber; +const int FileOptions::kCsharpNamespaceFieldNumber; const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER @@ -7052,6 +7055,7 @@ void FileOptions::SharedCtor() { deprecated_ = false; cc_enable_arenas_ = false; objc_class_prefix_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + csharp_namespace_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -7065,6 +7069,7 @@ void FileOptions::SharedDtor() { java_outer_classname_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); go_package_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); objc_class_prefix_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + csharp_namespace_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (this != default_instance_) { } } @@ -7117,11 +7122,14 @@ void FileOptions::Clear() { go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } } - if (_has_bits_[8 / 32] & 7936) { + if (_has_bits_[8 / 32] & 16128) { ZR_(java_generic_services_, cc_enable_arenas_); if (has_objc_class_prefix()) { objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } + if (has_csharp_namespace()) { + csharp_namespace_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + } } #undef ZR_HELPER_ @@ -7347,6 +7355,23 @@ bool FileOptions::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(298)) goto parse_csharp_namespace; + break; + } + + // optional string csharp_namespace = 37; + case 37: { + if (tag == 298) { + parse_csharp_namespace: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_csharp_namespace())); + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->csharp_namespace().data(), this->csharp_namespace().length(), + ::google::protobuf::internal::WireFormat::PARSE, + "google.protobuf.FileOptions.csharp_namespace"); + } else { + goto handle_unusual; + } if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } @@ -7481,6 +7506,16 @@ void FileOptions::SerializeWithCachedSizes( 36, this->objc_class_prefix(), output); } + // optional string csharp_namespace = 37; + if (has_csharp_namespace()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->csharp_namespace().data(), this->csharp_namespace().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.FileOptions.csharp_namespace"); + ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( + 37, this->csharp_namespace(), output); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) { ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( @@ -7591,6 +7626,17 @@ void FileOptions::SerializeWithCachedSizes( 36, this->objc_class_prefix(), target); } + // optional string csharp_namespace = 37; + if (has_csharp_namespace()) { + ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField( + this->csharp_namespace().data(), this->csharp_namespace().length(), + ::google::protobuf::internal::WireFormat::SERIALIZE, + "google.protobuf.FileOptions.csharp_namespace"); + target = + ::google::protobuf::internal::WireFormatLite::WriteStringToArray( + 37, this->csharp_namespace(), target); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) { target = ::google::protobuf::internal::WireFormatLite:: @@ -7662,7 +7708,7 @@ int FileOptions::ByteSize() const { } } - if (_has_bits_[8 / 32] & 7936) { + if (_has_bits_[8 / 32] & 16128) { // optional bool java_generic_services = 17 [default = false]; if (has_java_generic_services()) { total_size += 2 + 1; @@ -7690,6 +7736,13 @@ int FileOptions::ByteSize() const { this->objc_class_prefix()); } + // optional string csharp_namespace = 37; + if (has_csharp_namespace()) { + total_size += 2 + + ::google::protobuf::internal::WireFormatLite::StringSize( + this->csharp_namespace()); + } + } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); @@ -7773,6 +7826,10 @@ void FileOptions::MergeFrom(const FileOptions& from) { set_has_objc_class_prefix(); objc_class_prefix_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.objc_class_prefix_); } + if (from.has_csharp_namespace()) { + set_has_csharp_namespace(); + csharp_namespace_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.csharp_namespace_); + } } _extensions_.MergeFrom(from._extensions_); if (from._internal_metadata_.have_unknown_fields()) { @@ -7817,6 +7874,7 @@ void FileOptions::InternalSwap(FileOptions* other) { std::swap(deprecated_, other->deprecated_); std::swap(cc_enable_arenas_, other->cc_enable_arenas_); objc_class_prefix_.Swap(&other->objc_class_prefix_); + csharp_namespace_.Swap(&other->csharp_namespace_); uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); std::swap(_has_bits_[0], other->_has_bits_[0]); _internal_metadata_.Swap(&other->_internal_metadata_); @@ -8264,6 +8322,59 @@ void FileOptions::InternalSwap(FileOptions* other) { // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.objc_class_prefix) } +// optional string csharp_namespace = 37; + bool FileOptions::has_csharp_namespace() const { + return (_has_bits_[0] & 0x00002000u) != 0; +} + void FileOptions::set_has_csharp_namespace() { + _has_bits_[0] |= 0x00002000u; +} + void FileOptions::clear_has_csharp_namespace() { + _has_bits_[0] &= ~0x00002000u; +} + void FileOptions::clear_csharp_namespace() { + csharp_namespace_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + clear_has_csharp_namespace(); +} + const ::std::string& FileOptions::csharp_namespace() const { + // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.csharp_namespace) + return csharp_namespace_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void FileOptions::set_csharp_namespace(const ::std::string& value) { + set_has_csharp_namespace(); + csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.csharp_namespace) +} + void FileOptions::set_csharp_namespace(const char* value) { + set_has_csharp_namespace(); + csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.csharp_namespace) +} + void FileOptions::set_csharp_namespace(const char* value, size_t size) { + set_has_csharp_namespace(); + csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.csharp_namespace) +} + ::std::string* FileOptions::mutable_csharp_namespace() { + set_has_csharp_namespace(); + // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.csharp_namespace) + return csharp_namespace_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + ::std::string* FileOptions::release_csharp_namespace() { + clear_has_csharp_namespace(); + return csharp_namespace_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} + void FileOptions::set_allocated_csharp_namespace(::std::string* csharp_namespace) { + if (csharp_namespace != NULL) { + set_has_csharp_namespace(); + } else { + clear_has_csharp_namespace(); + } + csharp_namespace_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), csharp_namespace); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace) +} + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index d8cba659..5bebf4fd 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -1837,6 +1837,18 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { ::std::string* release_objc_class_prefix(); void set_allocated_objc_class_prefix(::std::string* objc_class_prefix); + // optional string csharp_namespace = 37; + bool has_csharp_namespace() const; + void clear_csharp_namespace(); + static const int kCsharpNamespaceFieldNumber = 37; + const ::std::string& csharp_namespace() const; + void set_csharp_namespace(const ::std::string& value); + void set_csharp_namespace(const char* value); + void set_csharp_namespace(const char* value, size_t size); + ::std::string* mutable_csharp_namespace(); + ::std::string* release_csharp_namespace(); + void set_allocated_csharp_namespace(::std::string* csharp_namespace); + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; int uninterpreted_option_size() const; void clear_uninterpreted_option(); @@ -1878,6 +1890,8 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline void clear_has_cc_enable_arenas(); inline void set_has_objc_class_prefix(); inline void clear_has_objc_class_prefix(); + inline void set_has_csharp_namespace(); + inline void clear_has_csharp_namespace(); ::google::protobuf::internal::ExtensionSet _extensions_; @@ -1893,6 +1907,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { int optimize_for_; ::google::protobuf::internal::ArenaStringPtr go_package_; ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_; + ::google::protobuf::internal::ArenaStringPtr csharp_namespace_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; bool java_generic_services_; bool py_generic_services_; @@ -5502,6 +5517,59 @@ inline void FileOptions::set_allocated_objc_class_prefix(::std::string* objc_cla // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.objc_class_prefix) } +// optional string csharp_namespace = 37; +inline bool FileOptions::has_csharp_namespace() const { + return (_has_bits_[0] & 0x00002000u) != 0; +} +inline void FileOptions::set_has_csharp_namespace() { + _has_bits_[0] |= 0x00002000u; +} +inline void FileOptions::clear_has_csharp_namespace() { + _has_bits_[0] &= ~0x00002000u; +} +inline void FileOptions::clear_csharp_namespace() { + csharp_namespace_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); + clear_has_csharp_namespace(); +} +inline const ::std::string& FileOptions::csharp_namespace() const { + // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.csharp_namespace) + return csharp_namespace_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void FileOptions::set_csharp_namespace(const ::std::string& value) { + set_has_csharp_namespace(); + csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); + // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.csharp_namespace) +} +inline void FileOptions::set_csharp_namespace(const char* value) { + set_has_csharp_namespace(); + csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); + // @@protoc_insertion_point(field_set_char:google.protobuf.FileOptions.csharp_namespace) +} +inline void FileOptions::set_csharp_namespace(const char* value, size_t size) { + set_has_csharp_namespace(); + csharp_namespace_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), + ::std::string(reinterpret_cast<const char*>(value), size)); + // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileOptions.csharp_namespace) +} +inline ::std::string* FileOptions::mutable_csharp_namespace() { + set_has_csharp_namespace(); + // @@protoc_insertion_point(field_mutable:google.protobuf.FileOptions.csharp_namespace) + return csharp_namespace_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline ::std::string* FileOptions::release_csharp_namespace() { + clear_has_csharp_namespace(); + return csharp_namespace_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); +} +inline void FileOptions::set_allocated_csharp_namespace(::std::string* csharp_namespace) { + if (csharp_namespace != NULL) { + set_has_csharp_namespace(); + } else { + clear_has_csharp_namespace(); + } + csharp_namespace_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), csharp_namespace); + // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace) +} + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 367b16e5..a4b64f65 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -351,6 +351,9 @@ message FileOptions { // generated classes from this .proto. There is no default. optional string objc_class_prefix = 36; + // Namespace for generated classes; defaults to the package. + optional string csharp_namespace = 37; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -481,8 +484,6 @@ message FieldOptions { // For Google-internal migration only. Do not use. optional bool weak = 10 [default=false]; - - // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; |