blob: 6cca6703222a4e97cecf68be6103be1c16ac20c0 [file] [log] [blame]
Jan Tattermusch685ae362015-03-16 19:07:16 -07001// 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 Luo90da3512015-06-03 18:02:17 -070033#include <map>
Jan Tattermusch685ae362015-03-16 19:07:16 -070034
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 Skeet67dd42c2015-10-01 10:36:58 +010045#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
Jan Tattermusch685ae362015-03-16 19:07:16 -070046#include <google/protobuf/compiler/csharp/csharp_enum.h>
Jan Tattermusch685ae362015-03-16 19:07:16 -070047#include <google/protobuf/compiler/csharp/csharp_field_base.h>
Jan Tattermuschcacbedf2015-07-10 13:40:34 -070048#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 Tattermusch685ae362015-03-16 19:07:16 -070051
52using google::protobuf::internal::scoped_ptr;
53
54namespace google {
55namespace protobuf {
56namespace compiler {
57namespace csharp {
58
59bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) {
60 return d1->number() < d2->number();
61}
62
63MessageGenerator::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
81MessageGenerator::~MessageGenerator() {
82}
83
84std::string MessageGenerator::class_name() {
Jan Tattermusch685ae362015-03-16 19:07:16 -070085 return descriptor_->name();
86}
87
88std::string MessageGenerator::full_class_name() {
89 return GetClassName(descriptor_);
90}
91
92const std::vector<std::string>& MessageGenerator::field_names() {
93 return field_names_;
94}
95
96const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() {
97 return fields_by_number_;
98}
99
Jie Luo90da3512015-06-03 18:02:17 -0700100void MessageGenerator::Generate(io::Printer* printer) {
101 map<string, string> vars;
102 vars["class_name"] = class_name();
103 vars["access_level"] = class_access_level();
Jie Luo90da3512015-06-03 18:02:17 -0700104
Jon Skeet67dd42c2015-10-01 10:36:58 +0100105 WriteMessageDocComment(printer, descriptor_);
Jie Luo90da3512015-06-03 18:02:17 -0700106 printer->Print(
Jon Skeetf5242682015-06-05 20:44:05 +0100107 "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
Jie Luo90da3512015-06-03 18:02:17 -0700108 WriteGeneratedCodeAttributes(printer);
109 printer->Print(
110 vars,
Jon Skeet8c896b22015-06-23 20:04:39 +0100111 "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$> {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700112 printer->Indent();
Jan Tattermusch685ae362015-03-16 19:07:16 -0700113
Jon Skeetf5242682015-06-05 20:44:05 +0100114 // All static fields and properties
115 printer->Print(
Jon Skeete38294a2015-06-09 19:30:44 +0100116 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 Luo90da3512015-06-03 18:02:17 -0700119
Jon Skeet78ea98f2015-07-01 14:47:03 +0100120 // Access the message descriptor via the relevant file descriptor or containing message descriptor.
121 if (!descriptor_->containing_type()) {
Jan Tattermusch43a2dee2015-07-29 20:15:03 -0700122 vars["descriptor_accessor"] = GetUmbrellaClassName(descriptor_->file())
Jon Skeet78ea98f2015-07-01 14:47:03 +0100123 + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]";
124 } else {
125 vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
126 + ".Descriptor.NestedTypes[" + SimpleItoa(descriptor_->index()) + "]";
127 }
128
Jon Skeetf5242682015-06-05 20:44:05 +0100129 printer->Print(
130 vars,
Jon Skeet9f37de92015-07-14 10:24:52 +0100131 "public static pbr::MessageDescriptor Descriptor {\n"
Jon Skeet78ea98f2015-07-01 14:47:03 +0100132 " get { return $descriptor_accessor$; }\n"
Jon Skeetf5242682015-06-05 20:44:05 +0100133 "}\n"
134 "\n"
Jon Skeet53c399a2015-07-20 19:24:31 +0100135 "pbr::MessageDescriptor pb::IMessage.Descriptor {\n"
136 " get { return Descriptor; }\n"
Jon Skeetf5242682015-06-05 20:44:05 +0100137 "}\n"
Jon Skeetf0327162015-07-30 13:15:45 +0100138 "\n");
Jon Skeetf5242682015-06-05 20:44:05 +0100139
Jon Skeet493e3db2015-07-01 17:11:17 +0100140 // Parameterless constructor and partial OnConstruction method.
Jon Skeetf5242682015-06-05 20:44:05 +0100141 printer->Print(
142 vars,
Jon Skeet493e3db2015-07-01 17:11:17 +0100143 "public $class_name$() {\n"
144 " OnConstruction();\n"
145 "}\n\n"
146 "partial void OnConstruction();\n\n");
Jon Skeetf5242682015-06-05 20:44:05 +0100147
Jon Skeet6c1fe6e2015-06-23 11:54:19 +0100148 GenerateCloningCode(printer);
Jon Skeetbfee2df2015-06-23 16:09:27 +0100149 GenerateFreezingCode(printer);
Jon Skeetf5242682015-06-05 20:44:05 +0100150
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 Skeet67dd42c2015-10-01 10:36:58 +0100157 "/// <summary>Field number for the \"$field_name$\" field.</summary>\n"
Jon Skeetf5242682015-06-05 20:44:05 +0100158 "public const int $field_constant_name$ = $index$;\n",
Jon Skeet67dd42c2015-10-01 10:36:58 +0100159 "field_name", fieldDescriptor->name(),
Jon Skeetf5242682015-06-05 20:44:05 +0100160 "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 Skeet53c399a2015-07-20 19:24:31 +0100172 vars["original_name"] = descriptor_->oneof_decl(i)->name();
Jie Luo90da3512015-06-03 18:02:17 -0700173 printer->Print(
174 vars,
Jon Skeetf5242682015-06-05 20:44:05 +0100175 "private object $name$_;\n"
Jon Skeet6bbbdfa2015-09-30 06:59:38 +0100176 "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n"
Jon Skeetf5242682015-06-05 20:44:05 +0100177 "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 Skeet67dd42c2015-10-01 10:36:58 +0100188 // TODO: Should we put the oneof .proto comments here? It's unclear exactly where they should go.
Jon Skeetf5242682015-06-05 20:44:05 +0100189 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 Skeete38294a2015-06-09 19:30:44 +0100195 "public void Clear$property_name$() {\n"
196 " $name$Case_ = $property_name$OneofCase.None;\n"
197 " $name$_ = null;\n"
Jon Skeetf5242682015-06-05 20:44:05 +0100198 "}\n\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700199 }
200
Jon Skeetf5242682015-06-05 20:44:05 +0100201 // Standard methods
Jon Skeete38294a2015-06-09 19:30:44 +0100202 GenerateFrameworkMethods(printer);
Jon Skeetf5242682015-06-05 20:44:05 +0100203 GenerateMessageSerializationMethods(printer);
204 GenerateMergingMethods(printer);
205
206 // Nested messages and enums
Jon Skeet541b4422015-07-15 13:36:56 +0100207 if (HasNestedGeneratedTypes()) {
Jon Skeet2212f562015-09-29 13:37:15 +0100208 printer->Print(
Jon Skeet1351d202015-09-29 14:34:05 +0100209 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 Luo90da3512015-06-03 18:02:17 -0700215 printer->Indent();
Jan Tattermusch685ae362015-03-16 19:07:16 -0700216 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
217 EnumGenerator enumGenerator(descriptor_->enum_type(i));
Jie Luo90da3512015-06-03 18:02:17 -0700218 enumGenerator.Generate(printer);
Jan Tattermusch685ae362015-03-16 19:07:16 -0700219 }
220 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
Jon Skeet541b4422015-07-15 13:36:56 +0100221 // Don't generate nested types for maps...
Jon Skeetdb52c9d2015-07-15 22:03:38 +0100222 if (!IsMapEntryMessage(descriptor_->nested_type(i))) {
223 MessageGenerator messageGenerator(descriptor_->nested_type(i));
224 messageGenerator.Generate(printer);
225 }
Jan Tattermusch685ae362015-03-16 19:07:16 -0700226 }
Jie Luo90da3512015-06-03 18:02:17 -0700227 printer->Outdent();
228 printer->Print("}\n"
229 "#endregion\n"
230 "\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700231 }
232
Jie Luo90da3512015-06-03 18:02:17 -0700233 printer->Outdent();
234 printer->Print("}\n");
235 printer->Print("\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700236}
237
Jon Skeet541b4422015-07-15 13:36:56 +0100238// 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.
240bool 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 Skeet6c1fe6e2015-06-23 11:54:19 +0100253void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
254 map<string, string> vars;
255 vars["class_name"] = class_name();
256 printer->Print(
257 vars,
Jon Skeet493e3db2015-07-01 17:11:17 +0100258 "public $class_name$($class_name$ other) : this() {\n");
Jon Skeet6c1fe6e2015-06-23 11:54:19 +0100259 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 Skeetbfee2df2015-06-23 16:09:27 +0100300void MessageGenerator::GenerateFreezingCode(io::Printer* printer) {
Jon Skeetbfee2df2015-06-23 16:09:27 +0100301}
302
Jon Skeete38294a2015-06-09 19:30:44 +0100303void 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 Skeet964627e2015-10-24 06:45:20 +0100326 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 Skeete38294a2015-06-09 19:30:44 +0100330 printer->Outdent();
331 printer->Print(
332 " return true;\n"
333 "}\n\n");
334
335 // GetHashCode
Jon Skeetdf44ae42015-06-25 12:08:18 +0100336 // Start with a non-zero value to easily distinguish between null and "empty" messages.
Jon Skeete38294a2015-06-09 19:30:44 +0100337 printer->Print(
338 "public override int GetHashCode() {\n"
Jon Skeetc1283312015-06-26 10:32:23 +0100339 " int hash = 1;\n");
Jon Skeete38294a2015-06-09 19:30:44 +0100340 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 Skeet964627e2015-10-24 06:45:20 +0100346 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 Skeete38294a2015-06-09 19:30:44 +0100350 printer->Print("return hash;\n");
351 printer->Outdent();
352 printer->Print("}\n\n");
353
Jon Skeet5b9288e2015-07-03 12:45:36 +0100354 printer->Print(
355 "public override string ToString() {\n"
356 " return pb::JsonFormatter.Default.Format(this);\n"
357 "}\n\n");
Jon Skeete38294a2015-06-09 19:30:44 +0100358}
359
Jie Luo90da3512015-06-03 18:02:17 -0700360void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) {
Jie Luo90da3512015-06-03 18:02:17 -0700361 printer->Print(
Jon Skeet96ddf012015-06-12 09:53:12 +0100362 "public void WriteTo(pb::CodedOutputStream output) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700363 printer->Indent();
Jon Skeetf5242682015-06-05 20:44:05 +0100364
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 Tattermusch685ae362015-03-16 19:07:16 -0700370 }
371
Jon Skeetf5242682015-06-05 20:44:05 +0100372 // TODO(jonskeet): Memoize size of frozen messages?
Jie Luo90da3512015-06-03 18:02:17 -0700373 printer->Outdent();
374 printer->Print(
375 "}\n"
376 "\n"
Jon Skeete38294a2015-06-09 19:30:44 +0100377 "public int CalculateSize() {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700378 printer->Indent();
Jon Skeetf5242682015-06-05 20:44:05 +0100379 printer->Print("int size = 0;\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700380 for (int i = 0; i < descriptor_->field_count(); i++) {
381 scoped_ptr<FieldGeneratorBase> generator(
382 CreateFieldGeneratorInternal(descriptor_->field(i)));
Jie Luo90da3512015-06-03 18:02:17 -0700383 generator->GenerateSerializedSizeCode(printer);
Jan Tattermusch685ae362015-03-16 19:07:16 -0700384 }
Jon Skeetf5242682015-06-05 20:44:05 +0100385 printer->Print("return size;\n");
Jie Luo90da3512015-06-03 18:02:17 -0700386 printer->Outdent();
Jon Skeet0d684d32015-06-24 17:21:55 +0100387 printer->Print("}\n\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700388}
389
Jon Skeetf5242682015-06-05 20:44:05 +0100390void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
Jan Tattermusch685ae362015-03-16 19:07:16 -0700391 // Note: These are separate from GenerateMessageSerializationMethods()
392 // because they need to be generated even for messages that are optimized
393 // for code size.
Jie Luo90da3512015-06-03 18:02:17 -0700394 map<string, string> vars;
395 vars["class_name"] = class_name();
Jan Tattermusch685ae362015-03-16 19:07:16 -0700396
Jie Luo90da3512015-06-03 18:02:17 -0700397 printer->Print(
398 vars,
Jon Skeete38294a2015-06-09 19:30:44 +0100399 "public void MergeFrom($class_name$ other) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700400 printer->Indent();
401 printer->Print(
Jon Skeetf5242682015-06-05 20:44:05 +0100402 "if (other == null) {\n"
403 " return;\n"
Jie Luo90da3512015-06-03 18:02:17 -0700404 "}\n");
Jon Skeetf5242682015-06-05 20:44:05 +0100405 // Merge non-oneof fields
Jan Tattermusch685ae362015-03-16 19:07:16 -0700406 for (int i = 0; i < descriptor_->field_count(); i++) {
Jon Skeetf5242682015-06-05 20:44:05 +0100407 if (!descriptor_->field(i)->containing_oneof()) {
408 scoped_ptr<FieldGeneratorBase> generator(
409 CreateFieldGeneratorInternal(descriptor_->field(i)));
410 generator->GenerateMergingCode(printer);
411 }
Jan Tattermusch685ae362015-03-16 19:07:16 -0700412 }
Jon Skeetf5242682015-06-05 20:44:05 +0100413 // 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 Luo90da3512015-06-03 18:02:17 -0700418 printer->Indent();
Jon Skeetf5242682015-06-05 20:44:05 +0100419 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 Tattermusch685ae362015-03-16 19:07:16 -0700427 }
Jie Luo90da3512015-06-03 18:02:17 -0700428 printer->Outdent();
429 printer->Print("}\n\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700430 }
Jon Skeetf5242682015-06-05 20:44:05 +0100431 printer->Outdent();
432 printer->Print("}\n\n");
Jon Skeet96ddf012015-06-12 09:53:12 +0100433 printer->Print("public void MergeFrom(pb::CodedInputStream input) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700434 printer->Indent();
Jie Luo90da3512015-06-03 18:02:17 -0700435 printer->Print(
436 "uint tag;\n"
Jon Skeetff334a62015-08-05 11:23:38 +0100437 "while ((tag = input.ReadTag()) != 0) {\n"
Jon Skeet96ddf012015-06-12 09:53:12 +0100438 " switch(tag) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700439 printer->Indent();
Jie Luo90da3512015-06-03 18:02:17 -0700440 printer->Indent();
441 printer->Print(
Jon Skeetf5242682015-06-05 20:44:05 +0100442 "default:\n"
Jon Skeete7f88ff2015-08-06 11:40:32 +0100443 " input.SkipLastField();\n" // We're not storing the data, but we still need to consume it.
Jon Skeet9df2def2015-08-04 11:26:48 +0100444 " break;\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700445 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 Skeete38294a2015-06-09 19:30:44 +0100450 // 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 Luo90da3512015-06-03 18:02:17 -0700455 printer->Print(
Jon Skeete38294a2015-06-09 19:30:44 +0100456 "case $packed_tag$:\n",
457 "packed_tag",
Jie Luo90da3512015-06-03 18:02:17 -0700458 SimpleItoa(
459 internal::WireFormatLite::MakeTag(
460 field->number(),
461 internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)));
Jan Tattermusch685ae362015-03-16 19:07:16 -0700462 }
463
Jie Luo90da3512015-06-03 18:02:17 -0700464 printer->Print("case $tag$: {\n", "tag", SimpleItoa(tag));
465 printer->Indent();
Jan Tattermusch685ae362015-03-16 19:07:16 -0700466 scoped_ptr<FieldGeneratorBase> generator(
467 CreateFieldGeneratorInternal(field));
Jie Luo90da3512015-06-03 18:02:17 -0700468 generator->GenerateParsingCode(printer);
469 printer->Print("break;\n");
470 printer->Outdent();
471 printer->Print("}\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700472 }
Jie Luo90da3512015-06-03 18:02:17 -0700473 printer->Outdent();
Jon Skeetf5242682015-06-05 20:44:05 +0100474 printer->Print("}\n"); // switch
Jie Luo90da3512015-06-03 18:02:17 -0700475 printer->Outdent();
Jon Skeetf5242682015-06-05 20:44:05 +0100476 printer->Print("}\n"); // while
Jie Luo90da3512015-06-03 18:02:17 -0700477 printer->Outdent();
Jon Skeetf5242682015-06-05 20:44:05 +0100478 printer->Print("}\n\n"); // method
Jan Tattermusch685ae362015-03-16 19:07:16 -0700479}
480
481int 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
491FieldGeneratorBase* 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