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 | |
52 | namespace google { |
53 | namespace protobuf { |
54 | namespace compiler { |
55 | namespace csharp { |
56 | |
57 | bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { |
58 | return d1->number() < d2->number(); |
59 | } |
60 | |
61 | MessageGenerator::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 | |
87 | MessageGenerator::~MessageGenerator() { |
88 | } |
89 | |
90 | std::string MessageGenerator::class_name() { |
91 | return descriptor_->name(); |
92 | } |
93 | |
94 | std::string MessageGenerator::full_class_name() { |
95 | return GetClassName(descriptor: descriptor_); |
96 | } |
97 | |
98 | const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() { |
99 | return fields_by_number_; |
100 | } |
101 | |
102 | void MessageGenerator::AddDeprecatedFlag(io::Printer* printer) { |
103 | if (descriptor_->options().deprecated()) { |
104 | printer->Print(text: "[global::System.ObsoleteAttribute]\n" ); |
105 | } |
106 | } |
107 | |
108 | void MessageGenerator::AddSerializableAttribute(io::Printer* printer) { |
109 | if (this->options()->serializable) { |
110 | printer->Print(text: "[global::System.SerializableAttribute]\n" ); |
111 | } |
112 | } |
113 | |
114 | void 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. |
363 | bool 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 | |
376 | void 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 | |
437 | void MessageGenerator::GenerateFreezingCode(io::Printer* printer) { |
438 | } |
439 | |
440 | void 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 | |
519 | void 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 | |
571 | void 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 | |
604 | void 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 | |
687 | void 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 |
752 | int 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 | |
771 | FieldGeneratorBase* 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 | |