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>
33#include <map>
34
35#include <google/protobuf/compiler/code_generator.h>
36#include <google/protobuf/descriptor.h>
37#include <google/protobuf/descriptor.pb.h>
38#include <google/protobuf/io/printer.h>
39#include <google/protobuf/io/zero_copy_stream.h>
40#include <google/protobuf/stubs/strutil.h>
41#include <google/protobuf/wire_format.h>
42#include <google/protobuf/wire_format_lite.h>
43
44#include <google/protobuf/compiler/csharp/csharp_options.h>
45#include <google/protobuf/compiler/csharp/csharp_doc_comment.h>
46#include <google/protobuf/compiler/csharp/csharp_enum.h>
47#include <google/protobuf/compiler/csharp/csharp_field_base.h>
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>
51
52namespace google {
53namespace protobuf {
54namespace compiler {
55namespace csharp {
56
57bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) {
58 return d1->number() < d2->number();
59}
60
61MessageGenerator::MessageGenerator(const Descriptor* descriptor,
62 const Options* options)
63 : SourceGeneratorBase(options),
64 descriptor_(descriptor),
65 has_bit_field_count_(0),
66 end_tag_(GetGroupEndTag(descriptor)),
67 has_extension_ranges_(descriptor->extension_range_count() > 0) {
68 // fields by number
69 for (int i = 0; i < descriptor_->field_count(); i++) {
70 fields_by_number_.push_back(x: descriptor_->field(index: i));
71 }
72 std::sort(first: fields_by_number_.begin(), last: fields_by_number_.end(),
73 comp: CompareFieldNumbers);
74
75 int presence_bit_count = 0;
76 for (int i = 0; i < descriptor_->field_count(); i++) {
77 const FieldDescriptor* field = descriptor_->field(index: i);
78 if (RequiresPresenceBit(descriptor: field)) {
79 presence_bit_count++;
80 if (has_bit_field_count_ == 0 || (presence_bit_count % 32) == 0) {
81 has_bit_field_count_++;
82 }
83 }
84 }
85}
86
87MessageGenerator::~MessageGenerator() {
88}
89
90std::string MessageGenerator::class_name() {
91 return descriptor_->name();
92}
93
94std::string MessageGenerator::full_class_name() {
95 return GetClassName(descriptor: descriptor_);
96}
97
98const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() {
99 return fields_by_number_;
100}
101
102void MessageGenerator::AddDeprecatedFlag(io::Printer* printer) {
103 if (descriptor_->options().deprecated()) {
104 printer->Print(text: "[global::System.ObsoleteAttribute]\n");
105 }
106}
107
108void MessageGenerator::AddSerializableAttribute(io::Printer* printer) {
109 if (this->options()->serializable) {
110 printer->Print(text: "[global::System.SerializableAttribute]\n");
111 }
112}
113
114void MessageGenerator::Generate(io::Printer* printer) {
115 std::map<std::string, std::string> vars;
116 vars["class_name"] = class_name();
117 vars["access_level"] = class_access_level();
118
119 WriteMessageDocComment(printer, message: descriptor_);
120 AddDeprecatedFlag(printer);
121 AddSerializableAttribute(printer);
122
123 printer->Print(
124 variables: vars,
125 text: "$access_level$ sealed partial class $class_name$ : ");
126
127 if (has_extension_ranges_) {
128 printer->Print(variables: vars, text: "pb::IExtendableMessage<$class_name$>\n");
129 }
130 else {
131 printer->Print(variables: vars, text: "pb::IMessage<$class_name$>\n");
132 }
133 printer->Print(text: "#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
134 printer->Print(text: " , pb::IBufferMessage\n");
135 printer->Print(text: "#endif\n");
136 printer->Print(text: "{\n");
137 printer->Indent();
138
139 // All static fields and properties
140 printer->Print(
141 variables: vars,
142 text: "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n");
143
144 printer->Print(
145 text: "private pb::UnknownFieldSet _unknownFields;\n");
146
147 if (has_extension_ranges_) {
148 if (IsDescriptorProto(descriptor: descriptor_->file())) {
149 printer->Print(variables: vars, text: "internal pb::ExtensionSet<$class_name$> _extensions;\n"); // CustomOptions compatibility
150 } else {
151 printer->Print(variables: vars, text: "private pb::ExtensionSet<$class_name$> _extensions;\n");
152 }
153
154 // a read-only property for fast
155 // retrieval of the set in IsInitialized
156 printer->Print(variables: vars,
157 text: "private pb::ExtensionSet<$class_name$> _Extensions { get { "
158 "return _extensions; } }\n");
159 }
160
161 for (int i = 0; i < has_bit_field_count_; i++) {
162 // don't use arrays since all arrays are heap allocated, saving allocations
163 // use ints instead of bytes since bytes lack bitwise operators, saving casts
164 printer->Print(text: "private int _hasBits$i$;\n", args: "i", args: StrCat(a: i));
165 }
166
167 WriteGeneratedCodeAttributes(printer);
168
169 printer->Print(
170 variables: vars,
171 text: "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n");
172
173 // Access the message descriptor via the relevant file descriptor or containing message descriptor.
174 if (!descriptor_->containing_type()) {
175 vars["descriptor_accessor"] = GetReflectionClassName(descriptor: descriptor_->file())
176 + ".Descriptor.MessageTypes[" + StrCat(a: descriptor_->index()) + "]";
177 } else {
178 vars["descriptor_accessor"] = GetClassName(descriptor: descriptor_->containing_type())
179 + ".Descriptor.NestedTypes[" + StrCat(a: descriptor_->index()) + "]";
180 }
181
182 WriteGeneratedCodeAttributes(printer);
183 printer->Print(
184 variables: vars,
185 text: "public static pbr::MessageDescriptor Descriptor {\n"
186 " get { return $descriptor_accessor$; }\n"
187 "}\n"
188 "\n");
189 WriteGeneratedCodeAttributes(printer);
190 printer->Print(
191 variables: vars,
192 text: "pbr::MessageDescriptor pb::IMessage.Descriptor {\n"
193 " get { return Descriptor; }\n"
194 "}\n"
195 "\n");
196
197 // Parameterless constructor and partial OnConstruction method.
198 WriteGeneratedCodeAttributes(printer);
199 printer->Print(
200 variables: vars,
201 text: "public $class_name$() {\n"
202 " OnConstruction();\n"
203 "}\n\n"
204 "partial void OnConstruction();\n\n");
205
206 GenerateCloningCode(printer);
207 GenerateFreezingCode(printer);
208
209 // Fields/properties
210 for (int i = 0; i < descriptor_->field_count(); i++) {
211 const FieldDescriptor* fieldDescriptor = descriptor_->field(index: i);
212
213 // Rats: we lose the debug comment here :(
214 printer->Print(
215 text: "/// <summary>Field number for the \"$field_name$\" field.</summary>\n"
216 "public const int $field_constant_name$ = $index$;\n",
217 args: "field_name", args: fieldDescriptor->name(),
218 args: "field_constant_name", args: GetFieldConstantName(field: fieldDescriptor),
219 args: "index", args: StrCat(a: fieldDescriptor->number()));
220 std::unique_ptr<FieldGeneratorBase> generator(
221 CreateFieldGeneratorInternal(descriptor: fieldDescriptor));
222 generator->GenerateMembers(printer);
223 printer->Print(text: "\n");
224 }
225
226 // oneof properties (for real oneofs, which come before synthetic ones)
227 for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) {
228 const OneofDescriptor* oneof = descriptor_->oneof_decl(index: i);
229 vars["name"] = UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: false);
230 vars["property_name"] = UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: true);
231 vars["original_name"] = oneof->name();
232 printer->Print(
233 variables: vars,
234 text: "private object $name$_;\n"
235 "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n"
236 "public enum $property_name$OneofCase {\n");
237 printer->Indent();
238 printer->Print(text: "None = 0,\n");
239 for (int j = 0; j < oneof->field_count(); j++) {
240 const FieldDescriptor* field = oneof->field(index: j);
241 printer->Print(text: "$oneof_case_name$ = $index$,\n",
242 args: "oneof_case_name", args: GetOneofCaseName(descriptor: field),
243 args: "index", args: StrCat(a: field->number()));
244 }
245 printer->Outdent();
246 printer->Print(text: "}\n");
247 // TODO: Should we put the oneof .proto comments here?
248 // It's unclear exactly where they should go.
249 printer->Print(
250 variables: vars,
251 text: "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n");
252 WriteGeneratedCodeAttributes(printer);
253 printer->Print(
254 variables: vars,
255 text: "public $property_name$OneofCase $property_name$Case {\n"
256 " get { return $name$Case_; }\n"
257 "}\n\n");
258 WriteGeneratedCodeAttributes(printer);
259 printer->Print(
260 variables: vars,
261 text: "public void Clear$property_name$() {\n"
262 " $name$Case_ = $property_name$OneofCase.None;\n"
263 " $name$_ = null;\n"
264 "}\n\n");
265 }
266
267 // Standard methods
268 GenerateFrameworkMethods(printer);
269 GenerateMessageSerializationMethods(printer);
270 GenerateMergingMethods(printer);
271
272 if (has_extension_ranges_) {
273 printer->Print(
274 variables: vars,
275 text: "public TValue GetExtension<TValue>(pb::Extension<$class_name$, "
276 "TValue> extension) {\n"
277 " return pb::ExtensionSet.Get(ref _extensions, extension);\n"
278 "}\n"
279 "public pbc::RepeatedField<TValue> "
280 "GetExtension<TValue>(pb::RepeatedExtension<$class_name$, TValue> "
281 "extension) {\n"
282 " return pb::ExtensionSet.Get(ref _extensions, extension);\n"
283 "}\n"
284 "public pbc::RepeatedField<TValue> "
285 "GetOrInitializeExtension<TValue>(pb::RepeatedExtension<$class_name$, "
286 "TValue> extension) {\n"
287 " return pb::ExtensionSet.GetOrInitialize(ref _extensions, "
288 "extension);\n"
289 "}\n"
290 "public void SetExtension<TValue>(pb::Extension<$class_name$, TValue> "
291 "extension, TValue value) {\n"
292 " pb::ExtensionSet.Set(ref _extensions, extension, value);\n"
293 "}\n"
294 "public bool HasExtension<TValue>(pb::Extension<$class_name$, TValue> "
295 "extension) {\n"
296 " return pb::ExtensionSet.Has(ref _extensions, extension);\n"
297 "}\n"
298 "public void ClearExtension<TValue>(pb::Extension<$class_name$, "
299 "TValue> extension) {\n"
300 " pb::ExtensionSet.Clear(ref _extensions, extension);\n"
301 "}\n"
302 "public void "
303 "ClearExtension<TValue>(pb::RepeatedExtension<$class_name$, TValue> "
304 "extension) {\n"
305 " pb::ExtensionSet.Clear(ref _extensions, extension);\n"
306 "}\n\n");
307 }
308
309 // Nested messages and enums
310 if (HasNestedGeneratedTypes()) {
311 printer->Print(
312 variables: vars,
313 text: "#region Nested types\n"
314 "/// <summary>Container for nested types declared in the $class_name$ message type.</summary>\n");
315 WriteGeneratedCodeAttributes(printer);
316 printer->Print(text: "public static partial class Types {\n");
317 printer->Indent();
318 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
319 EnumGenerator enumGenerator(descriptor_->enum_type(index: i), this->options());
320 enumGenerator.Generate(printer);
321 }
322 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
323 // Don't generate nested types for maps...
324 if (!IsMapEntryMessage(descriptor: descriptor_->nested_type(index: i))) {
325 MessageGenerator messageGenerator(
326 descriptor_->nested_type(index: i), this->options());
327 messageGenerator.Generate(printer);
328 }
329 }
330 printer->Outdent();
331 printer->Print(text: "}\n"
332 "#endregion\n"
333 "\n");
334 }
335
336 if (descriptor_->extension_count() > 0) {
337 printer->Print(
338 variables: vars,
339 text: "#region Extensions\n"
340 "/// <summary>Container for extensions for other messages declared in the $class_name$ message type.</summary>\n");
341 WriteGeneratedCodeAttributes(printer);
342 printer->Print(text: "public static partial class Extensions {\n");
343 printer->Indent();
344 for (int i = 0; i < descriptor_->extension_count(); i++) {
345 std::unique_ptr<FieldGeneratorBase> generator(
346 CreateFieldGeneratorInternal(descriptor: descriptor_->extension(index: i)));
347 generator->GenerateExtensionCode(printer);
348 }
349 printer->Outdent();
350 printer->Print(
351 text: "}\n"
352 "#endregion\n"
353 "\n");
354 }
355
356 printer->Outdent();
357 printer->Print(text: "}\n");
358 printer->Print(text: "\n");
359}
360
361// Helper to work out whether we need to generate a class to hold nested types/enums.
362// Only tricky because we don't want to generate map entry types.
363bool MessageGenerator::HasNestedGeneratedTypes()
364{
365 if (descriptor_->enum_type_count() > 0) {
366 return true;
367 }
368 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
369 if (!IsMapEntryMessage(descriptor: descriptor_->nested_type(index: i))) {
370 return true;
371 }
372 }
373 return false;
374}
375
376void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
377 std::map<std::string, std::string> vars;
378 WriteGeneratedCodeAttributes(printer);
379 vars["class_name"] = class_name();
380 printer->Print(
381 variables: vars,
382 text: "public $class_name$($class_name$ other) : this() {\n");
383 printer->Indent();
384 for (int i = 0; i < has_bit_field_count_; i++) {
385 printer->Print(text: "_hasBits$i$ = other._hasBits$i$;\n", args: "i", args: StrCat(a: i));
386 }
387 // Clone non-oneof fields first (treating optional proto3 fields as non-oneof)
388 for (int i = 0; i < descriptor_->field_count(); i++) {
389 const FieldDescriptor* field = descriptor_->field(index: i);
390 if (field->real_containing_oneof()) {
391 continue;
392 }
393 std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(descriptor: field));
394 generator->GenerateCloningCode(printer);
395 }
396 // Clone just the right field for each real oneof
397 for (int i = 0; i < descriptor_->real_oneof_decl_count(); ++i) {
398 const OneofDescriptor* oneof = descriptor_->oneof_decl(index: i);
399 vars["name"] = UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: false);
400 vars["property_name"] = UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: true);
401 printer->Print(variables: vars, text: "switch (other.$property_name$Case) {\n");
402 printer->Indent();
403 for (int j = 0; j < oneof->field_count(); j++) {
404 const FieldDescriptor* field = oneof->field(index: j);
405 std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(descriptor: field));
406 vars["oneof_case_name"] = GetOneofCaseName(descriptor: field);
407 printer->Print(
408 variables: vars,
409 text: "case $property_name$OneofCase.$oneof_case_name$:\n");
410 printer->Indent();
411 generator->GenerateCloningCode(printer);
412 printer->Print(text: "break;\n");
413 printer->Outdent();
414 }
415 printer->Outdent();
416 printer->Print(text: "}\n\n");
417 }
418 // Clone unknown fields
419 printer->Print(
420 text: "_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);\n");
421 if (has_extension_ranges_) {
422 printer->Print(
423 text: "_extensions = pb::ExtensionSet.Clone(other._extensions);\n");
424 }
425
426 printer->Outdent();
427 printer->Print(text: "}\n\n");
428
429 WriteGeneratedCodeAttributes(printer);
430 printer->Print(
431 variables: vars,
432 text: "public $class_name$ Clone() {\n"
433 " return new $class_name$(this);\n"
434 "}\n\n");
435}
436
437void MessageGenerator::GenerateFreezingCode(io::Printer* printer) {
438}
439
440void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
441 std::map<std::string, std::string> vars;
442 vars["class_name"] = class_name();
443
444 // Equality
445 WriteGeneratedCodeAttributes(printer);
446 printer->Print(
447 variables: vars,
448 text: "public override bool Equals(object other) {\n"
449 " return Equals(other as $class_name$);\n"
450 "}\n\n");
451 WriteGeneratedCodeAttributes(printer);
452 printer->Print(
453 variables: vars,
454 text: "public bool Equals($class_name$ other) {\n"
455 " if (ReferenceEquals(other, null)) {\n"
456 " return false;\n"
457 " }\n"
458 " if (ReferenceEquals(other, this)) {\n"
459 " return true;\n"
460 " }\n");
461 printer->Indent();
462 for (int i = 0; i < descriptor_->field_count(); i++) {
463 std::unique_ptr<FieldGeneratorBase> generator(
464 CreateFieldGeneratorInternal(descriptor: descriptor_->field(index: i)));
465 generator->WriteEquals(printer);
466 }
467 for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) {
468 printer->Print(text: "if ($property_name$Case != other.$property_name$Case) return false;\n",
469 args: "property_name", args: UnderscoresToCamelCase(input: descriptor_->oneof_decl(index: i)->name(), cap_next_letter: true));
470 }
471 if (has_extension_ranges_) {
472 printer->Print(
473 text: "if (!Equals(_extensions, other._extensions)) {\n"
474 " return false;\n"
475 "}\n");
476 }
477 printer->Outdent();
478 printer->Print(
479 text: " return Equals(_unknownFields, other._unknownFields);\n"
480 "}\n\n");
481
482 // GetHashCode
483 // Start with a non-zero value to easily distinguish between null and "empty" messages.
484 WriteGeneratedCodeAttributes(printer);
485 printer->Print(
486 text: "public override int GetHashCode() {\n"
487 " int hash = 1;\n");
488 printer->Indent();
489 for (int i = 0; i < descriptor_->field_count(); i++) {
490 std::unique_ptr<FieldGeneratorBase> generator(
491 CreateFieldGeneratorInternal(descriptor: descriptor_->field(index: i)));
492 generator->WriteHash(printer);
493 }
494 for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) {
495 printer->Print(text: "hash ^= (int) $name$Case_;\n",
496 args: "name", args: UnderscoresToCamelCase(input: descriptor_->oneof_decl(index: i)->name(), cap_next_letter: false));
497 }
498 if (has_extension_ranges_) {
499 printer->Print(
500 text: "if (_extensions != null) {\n"
501 " hash ^= _extensions.GetHashCode();\n"
502 "}\n");
503 }
504 printer->Print(
505 text: "if (_unknownFields != null) {\n"
506 " hash ^= _unknownFields.GetHashCode();\n"
507 "}\n"
508 "return hash;\n");
509 printer->Outdent();
510 printer->Print(text: "}\n\n");
511
512 WriteGeneratedCodeAttributes(printer);
513 printer->Print(
514 text: "public override string ToString() {\n"
515 " return pb::JsonFormatter.ToDiagnosticString(this);\n"
516 "}\n\n");
517}
518
519void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) {
520 WriteGeneratedCodeAttributes(printer);
521 printer->Print(
522 text: "public void WriteTo(pb::CodedOutputStream output) {\n");
523 printer->Print(text: "#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
524 printer->Indent();
525 printer->Print(text: "output.WriteRawMessage(this);\n");
526 printer->Outdent();
527 printer->Print(text: "#else\n");
528 printer->Indent();
529 GenerateWriteToBody(printer, use_write_context: false);
530 printer->Outdent();
531 printer->Print(text: "#endif\n");
532 printer->Print(text: "}\n\n");
533
534 printer->Print(text: "#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
535 WriteGeneratedCodeAttributes(printer);
536 printer->Print(text: "void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {\n");
537 printer->Indent();
538 GenerateWriteToBody(printer, use_write_context: true);
539 printer->Outdent();
540 printer->Print(text: "}\n");
541 printer->Print(text: "#endif\n\n");
542
543 WriteGeneratedCodeAttributes(printer);
544 printer->Print(
545 text: "public int CalculateSize() {\n");
546 printer->Indent();
547 printer->Print(text: "int size = 0;\n");
548 for (int i = 0; i < descriptor_->field_count(); i++) {
549 std::unique_ptr<FieldGeneratorBase> generator(
550 CreateFieldGeneratorInternal(descriptor: descriptor_->field(index: i)));
551 generator->GenerateSerializedSizeCode(printer);
552 }
553
554 if (has_extension_ranges_) {
555 printer->Print(
556 text: "if (_extensions != null) {\n"
557 " size += _extensions.CalculateSize();\n"
558 "}\n");
559 }
560
561 printer->Print(
562 text: "if (_unknownFields != null) {\n"
563 " size += _unknownFields.CalculateSize();\n"
564 "}\n");
565
566 printer->Print(text: "return size;\n");
567 printer->Outdent();
568 printer->Print(text: "}\n\n");
569}
570
571void MessageGenerator::GenerateWriteToBody(io::Printer* printer, bool use_write_context) {
572 // Serialize all the fields
573 for (int i = 0; i < fields_by_number().size(); i++) {
574 std::unique_ptr<FieldGeneratorBase> generator(
575 CreateFieldGeneratorInternal(descriptor: fields_by_number()[i]));
576 generator->GenerateSerializationCode(printer, use_write_context);
577 }
578
579 if (has_extension_ranges_) {
580 // Serialize extensions
581 printer->Print(
582 text: use_write_context
583 ? "if (_extensions != null) {\n"
584 " _extensions.WriteTo(ref output);\n"
585 "}\n"
586 : "if (_extensions != null) {\n"
587 " _extensions.WriteTo(output);\n"
588 "}\n");
589 }
590
591 // Serialize unknown fields
592 printer->Print(
593 text: use_write_context
594 ? "if (_unknownFields != null) {\n"
595 " _unknownFields.WriteTo(ref output);\n"
596 "}\n"
597 : "if (_unknownFields != null) {\n"
598 " _unknownFields.WriteTo(output);\n"
599 "}\n");
600
601 // TODO(jonskeet): Memoize size of frozen messages?
602}
603
604void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
605 // Note: These are separate from GenerateMessageSerializationMethods()
606 // because they need to be generated even for messages that are optimized
607 // for code size.
608 std::map<std::string, std::string> vars;
609 vars["class_name"] = class_name();
610
611 WriteGeneratedCodeAttributes(printer);
612 printer->Print(
613 variables: vars,
614 text: "public void MergeFrom($class_name$ other) {\n");
615 printer->Indent();
616 printer->Print(
617 text: "if (other == null) {\n"
618 " return;\n"
619 "}\n");
620 // Merge non-oneof fields, treating optional proto3 fields as normal fields
621 for (int i = 0; i < descriptor_->field_count(); i++) {
622 const FieldDescriptor* field = descriptor_->field(index: i);
623 if (field->real_containing_oneof()) {
624 continue;
625 }
626 std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(descriptor: field));
627 generator->GenerateMergingCode(printer);
628 }
629 // Merge oneof fields (for non-synthetic oneofs)
630 for (int i = 0; i < descriptor_->real_oneof_decl_count(); ++i) {
631 const OneofDescriptor* oneof = descriptor_->oneof_decl(index: i);
632 vars["name"] = UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: false);
633 vars["property_name"] = UnderscoresToCamelCase(input: oneof->name(), cap_next_letter: true);
634 printer->Print(variables: vars, text: "switch (other.$property_name$Case) {\n");
635 printer->Indent();
636 for (int j = 0; j < oneof->field_count(); j++) {
637 const FieldDescriptor* field = oneof->field(index: j);
638 vars["oneof_case_name"] = GetOneofCaseName(descriptor: field);
639 printer->Print(
640 variables: vars,
641 text: "case $property_name$OneofCase.$oneof_case_name$:\n");
642 printer->Indent();
643 std::unique_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(descriptor: field));
644 generator->GenerateMergingCode(printer);
645 printer->Print(text: "break;\n");
646 printer->Outdent();
647 }
648 printer->Outdent();
649 printer->Print(text: "}\n\n");
650 }
651 // Merge extensions
652 if (has_extension_ranges_) {
653 printer->Print(text: "pb::ExtensionSet.MergeFrom(ref _extensions, other._extensions);\n");
654 }
655
656 // Merge unknown fields.
657 printer->Print(
658 text: "_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);\n");
659
660 printer->Outdent();
661 printer->Print(text: "}\n\n");
662
663 WriteGeneratedCodeAttributes(printer);
664 printer->Print(text: "public void MergeFrom(pb::CodedInputStream input) {\n");
665 printer->Print(text: "#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
666 printer->Indent();
667 printer->Print(text: "input.ReadRawMessage(this);\n");
668 printer->Outdent();
669 printer->Print(text: "#else\n");
670 printer->Indent();
671 GenerateMainParseLoop(printer, use_parse_context: false);
672 printer->Outdent();
673 printer->Print(text: "#endif\n");
674 printer->Print(text: "}\n\n");
675
676 printer->Print(text: "#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE\n");
677 WriteGeneratedCodeAttributes(printer);
678 printer->Print(text: "void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {\n");
679 printer->Indent();
680 GenerateMainParseLoop(printer, use_parse_context: true);
681 printer->Outdent();
682 printer->Print(text: "}\n"); // method
683 printer->Print(text: "#endif\n\n");
684
685}
686
687void MessageGenerator::GenerateMainParseLoop(io::Printer* printer, bool use_parse_context) {
688 std::map<std::string, std::string> vars;
689 vars["maybe_ref_input"] = use_parse_context ? "ref input" : "input";
690
691 printer->Print(
692 text: "uint tag;\n"
693 "while ((tag = input.ReadTag()) != 0) {\n"
694 " switch(tag) {\n");
695 printer->Indent();
696 printer->Indent();
697 if (end_tag_ != 0) {
698 printer->Print(
699 text: "case $end_tag$:\n"
700 " return;\n",
701 args: "end_tag", args: StrCat(a: end_tag_));
702 }
703 if (has_extension_ranges_) {
704 printer->Print(variables: vars,
705 text: "default:\n"
706 " if (!pb::ExtensionSet.TryMergeFieldFrom(ref _extensions, $maybe_ref_input$)) {\n"
707 " _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, $maybe_ref_input$);\n"
708 " }\n"
709 " break;\n");
710 } else {
711 printer->Print(variables: vars,
712 text: "default:\n"
713 " _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, $maybe_ref_input$);\n"
714 " break;\n");
715 }
716 for (int i = 0; i < fields_by_number().size(); i++) {
717 const FieldDescriptor* field = fields_by_number()[i];
718 internal::WireFormatLite::WireType wt =
719 internal::WireFormat::WireTypeForFieldType(type: field->type());
720 uint32_t tag = internal::WireFormatLite::MakeTag(field_number: field->number(), type: wt);
721 // Handle both packed and unpacked repeated fields with the same Read*Array call;
722 // the two generated cases are the packed and unpacked tags.
723 // TODO(jonskeet): Check that is_packable is equivalent to
724 // is_repeated && wt in { VARINT, FIXED32, FIXED64 }.
725 // It looks like it is...
726 if (field->is_packable()) {
727 printer->Print(
728 text: "case $packed_tag$:\n",
729 args: "packed_tag",
730 args: StrCat(
731 a: internal::WireFormatLite::MakeTag(
732 field_number: field->number(),
733 type: internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)));
734 }
735
736 printer->Print(text: "case $tag$: {\n", args: "tag", args: StrCat(a: tag));
737 printer->Indent();
738 std::unique_ptr<FieldGeneratorBase> generator(
739 CreateFieldGeneratorInternal(descriptor: field));
740 generator->GenerateParsingCode(printer, use_parse_context);
741 printer->Print(text: "break;\n");
742 printer->Outdent();
743 printer->Print(text: "}\n");
744 }
745 printer->Outdent();
746 printer->Print(text: "}\n"); // switch
747 printer->Outdent();
748 printer->Print(text: "}\n"); // while
749}
750
751// it's a waste of space to track presence for all values, so we only track them if they're not nullable
752int MessageGenerator::GetPresenceIndex(const FieldDescriptor* descriptor) {
753 if (!RequiresPresenceBit(descriptor)) {
754 return -1;
755 }
756
757 int index = 0;
758 for (int i = 0; i < fields_by_number().size(); i++) {
759 const FieldDescriptor* field = fields_by_number()[i];
760 if (field == descriptor) {
761 return index;
762 }
763 if (RequiresPresenceBit(descriptor: field)) {
764 index++;
765 }
766 }
767 GOOGLE_LOG(DFATAL)<< "Could not find presence index for field " << descriptor->name();
768 return -1;
769}
770
771FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal(
772 const FieldDescriptor* descriptor) {
773 return CreateFieldGenerator(descriptor, presenceIndex: GetPresenceIndex(descriptor), options: this->options());
774}
775
776} // namespace csharp
777} // namespace compiler
778} // namespace protobuf
779} // namespace google
780