Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 1 | // Protocol Buffers - Google's data interchange format |
| 2 | // Copyright 2008 Google Inc. All rights reserved. |
| 3 | // https://developers.google.com/protocol-buffers/ |
| 4 | // |
| 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are |
| 7 | // met: |
| 8 | // |
| 9 | // * Redistributions of source code must retain the above copyright |
| 10 | // notice, this list of conditions and the following disclaimer. |
| 11 | // * Redistributions in binary form must reproduce the above |
| 12 | // copyright notice, this list of conditions and the following disclaimer |
| 13 | // in the documentation and/or other materials provided with the |
| 14 | // distribution. |
| 15 | // * Neither the name of Google Inc. nor the names of its |
| 16 | // contributors may be used to endorse or promote products derived from |
| 17 | // this software without specific prior written permission. |
| 18 | // |
| 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | |
| 31 | #include <sstream> |
| 32 | #include <algorithm> |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 33 | #include <map> |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 34 | |
| 35 | #include <google/protobuf/compiler/code_generator.h> |
| 36 | #include <google/protobuf/compiler/plugin.h> |
| 37 | #include <google/protobuf/descriptor.h> |
| 38 | #include <google/protobuf/descriptor.pb.h> |
| 39 | #include <google/protobuf/io/printer.h> |
| 40 | #include <google/protobuf/io/zero_copy_stream.h> |
| 41 | #include <google/protobuf/stubs/strutil.h> |
| 42 | #include <google/protobuf/wire_format.h> |
| 43 | #include <google/protobuf/wire_format_lite.h> |
| 44 | |
Jon Skeet | 67dd42c | 2015-10-01 10:36:58 +0100 | [diff] [blame] | 45 | #include <google/protobuf/compiler/csharp/csharp_doc_comment.h> |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 46 | #include <google/protobuf/compiler/csharp/csharp_enum.h> |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 47 | #include <google/protobuf/compiler/csharp/csharp_field_base.h> |
Jan Tattermusch | cacbedf | 2015-07-10 13:40:34 -0700 | [diff] [blame] | 48 | #include <google/protobuf/compiler/csharp/csharp_helpers.h> |
| 49 | #include <google/protobuf/compiler/csharp/csharp_message.h> |
| 50 | #include <google/protobuf/compiler/csharp/csharp_names.h> |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 51 | |
| 52 | using google::protobuf::internal::scoped_ptr; |
| 53 | |
| 54 | namespace google { |
| 55 | namespace protobuf { |
| 56 | namespace compiler { |
| 57 | namespace csharp { |
| 58 | |
| 59 | bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { |
| 60 | return d1->number() < d2->number(); |
| 61 | } |
| 62 | |
| 63 | MessageGenerator::MessageGenerator(const Descriptor* descriptor) |
| 64 | : SourceGeneratorBase(descriptor->file()), |
| 65 | descriptor_(descriptor) { |
| 66 | |
| 67 | // sorted field names |
| 68 | for (int i = 0; i < descriptor_->field_count(); i++) { |
| 69 | field_names_.push_back(descriptor_->field(i)->name()); |
| 70 | } |
| 71 | std::sort(field_names_.begin(), field_names_.end()); |
| 72 | |
| 73 | // fields by number |
| 74 | for (int i = 0; i < descriptor_->field_count(); i++) { |
| 75 | fields_by_number_.push_back(descriptor_->field(i)); |
| 76 | } |
| 77 | std::sort(fields_by_number_.begin(), fields_by_number_.end(), |
| 78 | CompareFieldNumbers); |
| 79 | } |
| 80 | |
| 81 | MessageGenerator::~MessageGenerator() { |
| 82 | } |
| 83 | |
| 84 | std::string MessageGenerator::class_name() { |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 85 | return descriptor_->name(); |
| 86 | } |
| 87 | |
| 88 | std::string MessageGenerator::full_class_name() { |
| 89 | return GetClassName(descriptor_); |
| 90 | } |
| 91 | |
| 92 | const std::vector<std::string>& MessageGenerator::field_names() { |
| 93 | return field_names_; |
| 94 | } |
| 95 | |
| 96 | const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() { |
| 97 | return fields_by_number_; |
| 98 | } |
| 99 | |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 100 | void MessageGenerator::Generate(io::Printer* printer) { |
| 101 | map<string, string> vars; |
| 102 | vars["class_name"] = class_name(); |
| 103 | vars["access_level"] = class_access_level(); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 104 | |
Jon Skeet | 67dd42c | 2015-10-01 10:36:58 +0100 | [diff] [blame] | 105 | WriteMessageDocComment(printer, descriptor_); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 106 | printer->Print( |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 107 | "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 108 | WriteGeneratedCodeAttributes(printer); |
| 109 | printer->Print( |
| 110 | vars, |
Jon Skeet | 8c896b2 | 2015-06-23 20:04:39 +0100 | [diff] [blame] | 111 | "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$> {\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 112 | printer->Indent(); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 113 | |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 114 | // All static fields and properties |
| 115 | printer->Print( |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 116 | vars, |
| 117 | "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n" |
| 118 | "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 119 | |
Jon Skeet | 78ea98f | 2015-07-01 14:47:03 +0100 | [diff] [blame] | 120 | // Access the message descriptor via the relevant file descriptor or containing message descriptor. |
| 121 | if (!descriptor_->containing_type()) { |
Jan Tattermusch | 43a2dee | 2015-07-29 20:15:03 -0700 | [diff] [blame] | 122 | vars["descriptor_accessor"] = GetUmbrellaClassName(descriptor_->file()) |
Jon Skeet | 78ea98f | 2015-07-01 14:47:03 +0100 | [diff] [blame] | 123 | + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]"; |
| 124 | } else { |
| 125 | vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type()) |
| 126 | + ".Descriptor.NestedTypes[" + SimpleItoa(descriptor_->index()) + "]"; |
| 127 | } |
| 128 | |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 129 | printer->Print( |
| 130 | vars, |
Jon Skeet | 9f37de9 | 2015-07-14 10:24:52 +0100 | [diff] [blame] | 131 | "public static pbr::MessageDescriptor Descriptor {\n" |
Jon Skeet | 78ea98f | 2015-07-01 14:47:03 +0100 | [diff] [blame] | 132 | " get { return $descriptor_accessor$; }\n" |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 133 | "}\n" |
| 134 | "\n" |
Jon Skeet | 53c399a | 2015-07-20 19:24:31 +0100 | [diff] [blame] | 135 | "pbr::MessageDescriptor pb::IMessage.Descriptor {\n" |
| 136 | " get { return Descriptor; }\n" |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 137 | "}\n" |
Jon Skeet | f032716 | 2015-07-30 13:15:45 +0100 | [diff] [blame] | 138 | "\n"); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 139 | |
Jon Skeet | 493e3db | 2015-07-01 17:11:17 +0100 | [diff] [blame] | 140 | // Parameterless constructor and partial OnConstruction method. |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 141 | printer->Print( |
| 142 | vars, |
Jon Skeet | 493e3db | 2015-07-01 17:11:17 +0100 | [diff] [blame] | 143 | "public $class_name$() {\n" |
| 144 | " OnConstruction();\n" |
| 145 | "}\n\n" |
| 146 | "partial void OnConstruction();\n\n"); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 147 | |
Jon Skeet | 6c1fe6e | 2015-06-23 11:54:19 +0100 | [diff] [blame] | 148 | GenerateCloningCode(printer); |
Jon Skeet | bfee2df | 2015-06-23 16:09:27 +0100 | [diff] [blame] | 149 | GenerateFreezingCode(printer); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 150 | |
| 151 | // Fields/properties |
| 152 | for (int i = 0; i < descriptor_->field_count(); i++) { |
| 153 | const FieldDescriptor* fieldDescriptor = descriptor_->field(i); |
| 154 | |
| 155 | // Rats: we lose the debug comment here :( |
| 156 | printer->Print( |
Jon Skeet | 67dd42c | 2015-10-01 10:36:58 +0100 | [diff] [blame] | 157 | "/// <summary>Field number for the \"$field_name$\" field.</summary>\n" |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 158 | "public const int $field_constant_name$ = $index$;\n", |
Jon Skeet | 67dd42c | 2015-10-01 10:36:58 +0100 | [diff] [blame] | 159 | "field_name", fieldDescriptor->name(), |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 160 | "field_constant_name", GetFieldConstantName(fieldDescriptor), |
| 161 | "index", SimpleItoa(fieldDescriptor->number())); |
| 162 | scoped_ptr<FieldGeneratorBase> generator( |
| 163 | CreateFieldGeneratorInternal(fieldDescriptor)); |
| 164 | generator->GenerateMembers(printer); |
| 165 | printer->Print("\n"); |
| 166 | } |
| 167 | |
| 168 | // oneof properties |
| 169 | for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { |
| 170 | vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); |
| 171 | vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); |
Jon Skeet | 53c399a | 2015-07-20 19:24:31 +0100 | [diff] [blame] | 172 | vars["original_name"] = descriptor_->oneof_decl(i)->name(); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 173 | printer->Print( |
| 174 | vars, |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 175 | "private object $name$_;\n" |
Jon Skeet | 6bbbdfa | 2015-09-30 06:59:38 +0100 | [diff] [blame] | 176 | "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n" |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 177 | "public enum $property_name$OneofCase {\n"); |
| 178 | printer->Indent(); |
| 179 | printer->Print("None = 0,\n"); |
| 180 | for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { |
| 181 | const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); |
| 182 | printer->Print("$field_property_name$ = $index$,\n", |
| 183 | "field_property_name", GetPropertyName(field), |
| 184 | "index", SimpleItoa(field->number())); |
| 185 | } |
| 186 | printer->Outdent(); |
| 187 | printer->Print("}\n"); |
Jon Skeet | 67dd42c | 2015-10-01 10:36:58 +0100 | [diff] [blame] | 188 | // TODO: Should we put the oneof .proto comments here? It's unclear exactly where they should go. |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 189 | printer->Print( |
| 190 | vars, |
| 191 | "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n" |
| 192 | "public $property_name$OneofCase $property_name$Case {\n" |
| 193 | " get { return $name$Case_; }\n" |
| 194 | "}\n\n" |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 195 | "public void Clear$property_name$() {\n" |
| 196 | " $name$Case_ = $property_name$OneofCase.None;\n" |
| 197 | " $name$_ = null;\n" |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 198 | "}\n\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 199 | } |
| 200 | |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 201 | // Standard methods |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 202 | GenerateFrameworkMethods(printer); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 203 | GenerateMessageSerializationMethods(printer); |
| 204 | GenerateMergingMethods(printer); |
| 205 | |
| 206 | // Nested messages and enums |
Jon Skeet | 541b442 | 2015-07-15 13:36:56 +0100 | [diff] [blame] | 207 | if (HasNestedGeneratedTypes()) { |
Jon Skeet | 2212f56 | 2015-09-29 13:37:15 +0100 | [diff] [blame] | 208 | printer->Print( |
Jon Skeet | 1351d20 | 2015-09-29 14:34:05 +0100 | [diff] [blame] | 209 | vars, |
| 210 | "#region Nested types\n" |
| 211 | "/// <summary>Container for nested types declared in the $class_name$ message type.</summary>\n" |
| 212 | "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n"); |
| 213 | WriteGeneratedCodeAttributes(printer); |
| 214 | printer->Print("public static partial class Types {\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 215 | printer->Indent(); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 216 | for (int i = 0; i < descriptor_->enum_type_count(); i++) { |
| 217 | EnumGenerator enumGenerator(descriptor_->enum_type(i)); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 218 | enumGenerator.Generate(printer); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 219 | } |
| 220 | for (int i = 0; i < descriptor_->nested_type_count(); i++) { |
Jon Skeet | 541b442 | 2015-07-15 13:36:56 +0100 | [diff] [blame] | 221 | // Don't generate nested types for maps... |
Jon Skeet | db52c9d | 2015-07-15 22:03:38 +0100 | [diff] [blame] | 222 | if (!IsMapEntryMessage(descriptor_->nested_type(i))) { |
| 223 | MessageGenerator messageGenerator(descriptor_->nested_type(i)); |
| 224 | messageGenerator.Generate(printer); |
| 225 | } |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 226 | } |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 227 | printer->Outdent(); |
| 228 | printer->Print("}\n" |
| 229 | "#endregion\n" |
| 230 | "\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 231 | } |
| 232 | |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 233 | printer->Outdent(); |
| 234 | printer->Print("}\n"); |
| 235 | printer->Print("\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 236 | } |
| 237 | |
Jon Skeet | 541b442 | 2015-07-15 13:36:56 +0100 | [diff] [blame] | 238 | // Helper to work out whether we need to generate a class to hold nested types/enums. |
| 239 | // Only tricky because we don't want to generate map entry types. |
| 240 | bool MessageGenerator::HasNestedGeneratedTypes() |
| 241 | { |
| 242 | if (descriptor_->enum_type_count() > 0) { |
| 243 | return true; |
| 244 | } |
| 245 | for (int i = 0; i < descriptor_->nested_type_count(); i++) { |
| 246 | if (!IsMapEntryMessage(descriptor_->nested_type(i))) { |
| 247 | return true; |
| 248 | } |
| 249 | } |
| 250 | return false; |
| 251 | } |
| 252 | |
Jon Skeet | 6c1fe6e | 2015-06-23 11:54:19 +0100 | [diff] [blame] | 253 | void MessageGenerator::GenerateCloningCode(io::Printer* printer) { |
| 254 | map<string, string> vars; |
| 255 | vars["class_name"] = class_name(); |
| 256 | printer->Print( |
| 257 | vars, |
Jon Skeet | 493e3db | 2015-07-01 17:11:17 +0100 | [diff] [blame] | 258 | "public $class_name$($class_name$ other) : this() {\n"); |
Jon Skeet | 6c1fe6e | 2015-06-23 11:54:19 +0100 | [diff] [blame] | 259 | printer->Indent(); |
| 260 | // Clone non-oneof fields first |
| 261 | for (int i = 0; i < descriptor_->field_count(); i++) { |
| 262 | if (!descriptor_->field(i)->containing_oneof()) { |
| 263 | scoped_ptr<FieldGeneratorBase> generator( |
| 264 | CreateFieldGeneratorInternal(descriptor_->field(i))); |
| 265 | generator->GenerateCloningCode(printer); |
| 266 | } |
| 267 | } |
| 268 | // Clone just the right field for each oneof |
| 269 | for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { |
| 270 | vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); |
| 271 | vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); |
| 272 | printer->Print(vars, "switch (other.$property_name$Case) {\n"); |
| 273 | printer->Indent(); |
| 274 | for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { |
| 275 | const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); |
| 276 | scoped_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field)); |
| 277 | vars["field_property_name"] = GetPropertyName(field); |
| 278 | printer->Print( |
| 279 | vars, |
| 280 | "case $property_name$OneofCase.$field_property_name$:\n"); |
| 281 | printer->Indent(); |
| 282 | generator->GenerateCloningCode(printer); |
| 283 | printer->Print("break;\n"); |
| 284 | printer->Outdent(); |
| 285 | } |
| 286 | printer->Outdent(); |
| 287 | printer->Print("}\n\n"); |
| 288 | } |
| 289 | |
| 290 | printer->Outdent(); |
| 291 | printer->Print("}\n\n"); |
| 292 | |
| 293 | printer->Print( |
| 294 | vars, |
| 295 | "public $class_name$ Clone() {\n" |
| 296 | " return new $class_name$(this);\n" |
| 297 | "}\n\n"); |
| 298 | } |
| 299 | |
Jon Skeet | bfee2df | 2015-06-23 16:09:27 +0100 | [diff] [blame] | 300 | void MessageGenerator::GenerateFreezingCode(io::Printer* printer) { |
Jon Skeet | bfee2df | 2015-06-23 16:09:27 +0100 | [diff] [blame] | 301 | } |
| 302 | |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 303 | void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) { |
| 304 | map<string, string> vars; |
| 305 | vars["class_name"] = class_name(); |
| 306 | |
| 307 | // Equality |
| 308 | printer->Print( |
| 309 | vars, |
| 310 | "public override bool Equals(object other) {\n" |
| 311 | " return Equals(other as $class_name$);\n" |
| 312 | "}\n\n" |
| 313 | "public bool Equals($class_name$ other) {\n" |
| 314 | " if (ReferenceEquals(other, null)) {\n" |
| 315 | " return false;\n" |
| 316 | " }\n" |
| 317 | " if (ReferenceEquals(other, this)) {\n" |
| 318 | " return true;\n" |
| 319 | " }\n"); |
| 320 | printer->Indent(); |
| 321 | for (int i = 0; i < descriptor_->field_count(); i++) { |
| 322 | scoped_ptr<FieldGeneratorBase> generator( |
| 323 | CreateFieldGeneratorInternal(descriptor_->field(i))); |
| 324 | generator->WriteEquals(printer); |
| 325 | } |
Jon Skeet | 964627e | 2015-10-24 06:45:20 +0100 | [diff] [blame^] | 326 | for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { |
| 327 | printer->Print("if ($property_name$Case != other.$property_name$Case) return false;\n", |
| 328 | "property_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true)); |
| 329 | } |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 330 | printer->Outdent(); |
| 331 | printer->Print( |
| 332 | " return true;\n" |
| 333 | "}\n\n"); |
| 334 | |
| 335 | // GetHashCode |
Jon Skeet | df44ae4 | 2015-06-25 12:08:18 +0100 | [diff] [blame] | 336 | // Start with a non-zero value to easily distinguish between null and "empty" messages. |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 337 | printer->Print( |
| 338 | "public override int GetHashCode() {\n" |
Jon Skeet | c128331 | 2015-06-26 10:32:23 +0100 | [diff] [blame] | 339 | " int hash = 1;\n"); |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 340 | printer->Indent(); |
| 341 | for (int i = 0; i < descriptor_->field_count(); i++) { |
| 342 | scoped_ptr<FieldGeneratorBase> generator( |
| 343 | CreateFieldGeneratorInternal(descriptor_->field(i))); |
| 344 | generator->WriteHash(printer); |
| 345 | } |
Jon Skeet | 964627e | 2015-10-24 06:45:20 +0100 | [diff] [blame^] | 346 | for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { |
| 347 | printer->Print("hash ^= (int) $name$Case_;\n", |
| 348 | "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false)); |
| 349 | } |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 350 | printer->Print("return hash;\n"); |
| 351 | printer->Outdent(); |
| 352 | printer->Print("}\n\n"); |
| 353 | |
Jon Skeet | 5b9288e | 2015-07-03 12:45:36 +0100 | [diff] [blame] | 354 | printer->Print( |
| 355 | "public override string ToString() {\n" |
| 356 | " return pb::JsonFormatter.Default.Format(this);\n" |
| 357 | "}\n\n"); |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 358 | } |
| 359 | |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 360 | void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) { |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 361 | printer->Print( |
Jon Skeet | 96ddf01 | 2015-06-12 09:53:12 +0100 | [diff] [blame] | 362 | "public void WriteTo(pb::CodedOutputStream output) {\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 363 | printer->Indent(); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 364 | |
| 365 | // Serialize all the fields |
| 366 | for (int i = 0; i < fields_by_number().size(); i++) { |
| 367 | scoped_ptr<FieldGeneratorBase> generator( |
| 368 | CreateFieldGeneratorInternal(fields_by_number()[i])); |
| 369 | generator->GenerateSerializationCode(printer); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 370 | } |
| 371 | |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 372 | // TODO(jonskeet): Memoize size of frozen messages? |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 373 | printer->Outdent(); |
| 374 | printer->Print( |
| 375 | "}\n" |
| 376 | "\n" |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 377 | "public int CalculateSize() {\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 378 | printer->Indent(); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 379 | printer->Print("int size = 0;\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 380 | for (int i = 0; i < descriptor_->field_count(); i++) { |
| 381 | scoped_ptr<FieldGeneratorBase> generator( |
| 382 | CreateFieldGeneratorInternal(descriptor_->field(i))); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 383 | generator->GenerateSerializedSizeCode(printer); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 384 | } |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 385 | printer->Print("return size;\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 386 | printer->Outdent(); |
Jon Skeet | 0d684d3 | 2015-06-24 17:21:55 +0100 | [diff] [blame] | 387 | printer->Print("}\n\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 388 | } |
| 389 | |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 390 | void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 391 | // Note: These are separate from GenerateMessageSerializationMethods() |
| 392 | // because they need to be generated even for messages that are optimized |
| 393 | // for code size. |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 394 | map<string, string> vars; |
| 395 | vars["class_name"] = class_name(); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 396 | |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 397 | printer->Print( |
| 398 | vars, |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 399 | "public void MergeFrom($class_name$ other) {\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 400 | printer->Indent(); |
| 401 | printer->Print( |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 402 | "if (other == null) {\n" |
| 403 | " return;\n" |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 404 | "}\n"); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 405 | // Merge non-oneof fields |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 406 | for (int i = 0; i < descriptor_->field_count(); i++) { |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 407 | if (!descriptor_->field(i)->containing_oneof()) { |
| 408 | scoped_ptr<FieldGeneratorBase> generator( |
| 409 | CreateFieldGeneratorInternal(descriptor_->field(i))); |
| 410 | generator->GenerateMergingCode(printer); |
| 411 | } |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 412 | } |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 413 | // Merge oneof fields |
| 414 | for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { |
| 415 | vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); |
| 416 | vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); |
| 417 | printer->Print(vars, "switch (other.$property_name$Case) {\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 418 | printer->Indent(); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 419 | for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { |
| 420 | const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); |
| 421 | vars["field_property_name"] = GetPropertyName(field); |
| 422 | printer->Print( |
| 423 | vars, |
| 424 | "case $property_name$OneofCase.$field_property_name$:\n" |
| 425 | " $field_property_name$ = other.$field_property_name$;\n" |
| 426 | " break;\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 427 | } |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 428 | printer->Outdent(); |
| 429 | printer->Print("}\n\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 430 | } |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 431 | printer->Outdent(); |
| 432 | printer->Print("}\n\n"); |
Jon Skeet | 96ddf01 | 2015-06-12 09:53:12 +0100 | [diff] [blame] | 433 | printer->Print("public void MergeFrom(pb::CodedInputStream input) {\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 434 | printer->Indent(); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 435 | printer->Print( |
| 436 | "uint tag;\n" |
Jon Skeet | ff334a6 | 2015-08-05 11:23:38 +0100 | [diff] [blame] | 437 | "while ((tag = input.ReadTag()) != 0) {\n" |
Jon Skeet | 96ddf01 | 2015-06-12 09:53:12 +0100 | [diff] [blame] | 438 | " switch(tag) {\n"); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 439 | printer->Indent(); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 440 | printer->Indent(); |
| 441 | printer->Print( |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 442 | "default:\n" |
Jon Skeet | e7f88ff | 2015-08-06 11:40:32 +0100 | [diff] [blame] | 443 | " input.SkipLastField();\n" // We're not storing the data, but we still need to consume it. |
Jon Skeet | 9df2def | 2015-08-04 11:26:48 +0100 | [diff] [blame] | 444 | " break;\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 445 | for (int i = 0; i < fields_by_number().size(); i++) { |
| 446 | const FieldDescriptor* field = fields_by_number()[i]; |
| 447 | internal::WireFormatLite::WireType wt = |
| 448 | internal::WireFormat::WireTypeForFieldType(field->type()); |
| 449 | uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt); |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 450 | // Handle both packed and unpacked repeated fields with the same Read*Array call; |
| 451 | // the two generated cases are the packed and unpacked tags. |
| 452 | // TODO(jonskeet): Check that is_packable is equivalent to is_repeated && wt in { VARINT, FIXED32, FIXED64 }. |
| 453 | // It looks like it is... |
| 454 | if (field->is_packable()) { |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 455 | printer->Print( |
Jon Skeet | e38294a | 2015-06-09 19:30:44 +0100 | [diff] [blame] | 456 | "case $packed_tag$:\n", |
| 457 | "packed_tag", |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 458 | SimpleItoa( |
| 459 | internal::WireFormatLite::MakeTag( |
| 460 | field->number(), |
| 461 | internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED))); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 462 | } |
| 463 | |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 464 | printer->Print("case $tag$: {\n", "tag", SimpleItoa(tag)); |
| 465 | printer->Indent(); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 466 | scoped_ptr<FieldGeneratorBase> generator( |
| 467 | CreateFieldGeneratorInternal(field)); |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 468 | generator->GenerateParsingCode(printer); |
| 469 | printer->Print("break;\n"); |
| 470 | printer->Outdent(); |
| 471 | printer->Print("}\n"); |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 472 | } |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 473 | printer->Outdent(); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 474 | printer->Print("}\n"); // switch |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 475 | printer->Outdent(); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 476 | printer->Print("}\n"); // while |
Jie Luo | 90da351 | 2015-06-03 18:02:17 -0700 | [diff] [blame] | 477 | printer->Outdent(); |
Jon Skeet | f524268 | 2015-06-05 20:44:05 +0100 | [diff] [blame] | 478 | printer->Print("}\n\n"); // method |
Jan Tattermusch | 685ae36 | 2015-03-16 19:07:16 -0700 | [diff] [blame] | 479 | } |
| 480 | |
| 481 | int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) { |
| 482 | for (int i = 0; i < field_names().size(); i++) { |
| 483 | if (field_names()[i] == descriptor->name()) { |
| 484 | return i; |
| 485 | } |
| 486 | } |
| 487 | GOOGLE_LOG(DFATAL)<< "Could not find ordinal for field " << descriptor->name(); |
| 488 | return -1; |
| 489 | } |
| 490 | |
| 491 | FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal( |
| 492 | const FieldDescriptor* descriptor) { |
| 493 | return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor)); |
| 494 | } |
| 495 | |
| 496 | } // namespace csharp |
| 497 | } // namespace compiler |
| 498 | } // namespace protobuf |
| 499 | } // namespace google |