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/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
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 using google::protobuf::internal::scoped_ptr;
53
54 namespace google {
55 namespace protobuf {
56 namespace compiler {
57 namespace csharp {
58
CompareFieldNumbers(const FieldDescriptor * d1,const FieldDescriptor * d2)59 bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) {
60 return d1->number() < d2->number();
61 }
62
MessageGenerator(const Descriptor * descriptor,const Options * options)63 MessageGenerator::MessageGenerator(const Descriptor* descriptor,
64 const Options* options)
65 : SourceGeneratorBase(descriptor->file(), options),
66 descriptor_(descriptor) {
67
68 // sorted field names
69 for (int i = 0; i < descriptor_->field_count(); i++) {
70 field_names_.push_back(descriptor_->field(i)->name());
71 }
72 std::sort(field_names_.begin(), field_names_.end());
73
74 // fields by number
75 for (int i = 0; i < descriptor_->field_count(); i++) {
76 fields_by_number_.push_back(descriptor_->field(i));
77 }
78 std::sort(fields_by_number_.begin(), fields_by_number_.end(),
79 CompareFieldNumbers);
80 }
81
~MessageGenerator()82 MessageGenerator::~MessageGenerator() {
83 }
84
class_name()85 std::string MessageGenerator::class_name() {
86 return descriptor_->name();
87 }
88
full_class_name()89 std::string MessageGenerator::full_class_name() {
90 return GetClassName(descriptor_);
91 }
92
field_names()93 const std::vector<std::string>& MessageGenerator::field_names() {
94 return field_names_;
95 }
96
fields_by_number()97 const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() {
98 return fields_by_number_;
99 }
100
Generate(io::Printer * printer)101 void MessageGenerator::Generate(io::Printer* printer) {
102 map<string, string> vars;
103 vars["class_name"] = class_name();
104 vars["access_level"] = class_access_level();
105
106 WriteMessageDocComment(printer, descriptor_);
107 printer->Print(
108 vars,
109 "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$> {\n");
110 printer->Indent();
111
112 // All static fields and properties
113 printer->Print(
114 vars,
115 "private static readonly pb::MessageParser<$class_name$> _parser = new pb::MessageParser<$class_name$>(() => new $class_name$());\n");
116
117 WriteGeneratedCodeAttributes(printer);
118 printer->Print(
119 vars,
120 "public static pb::MessageParser<$class_name$> Parser { get { return _parser; } }\n\n");
121
122 // Access the message descriptor via the relevant file descriptor or containing message descriptor.
123 if (!descriptor_->containing_type()) {
124 vars["descriptor_accessor"] = GetReflectionClassName(descriptor_->file())
125 + ".Descriptor.MessageTypes[" + SimpleItoa(descriptor_->index()) + "]";
126 } else {
127 vars["descriptor_accessor"] = GetClassName(descriptor_->containing_type())
128 + ".Descriptor.NestedTypes[" + SimpleItoa(descriptor_->index()) + "]";
129 }
130
131 WriteGeneratedCodeAttributes(printer);
132 printer->Print(
133 vars,
134 "public static pbr::MessageDescriptor Descriptor {\n"
135 " get { return $descriptor_accessor$; }\n"
136 "}\n"
137 "\n");
138 WriteGeneratedCodeAttributes(printer);
139 printer->Print(
140 vars,
141 "pbr::MessageDescriptor pb::IMessage.Descriptor {\n"
142 " get { return Descriptor; }\n"
143 "}\n"
144 "\n");
145
146 // Parameterless constructor and partial OnConstruction method.
147 WriteGeneratedCodeAttributes(printer);
148 printer->Print(
149 vars,
150 "public $class_name$() {\n"
151 " OnConstruction();\n"
152 "}\n\n"
153 "partial void OnConstruction();\n\n");
154
155 GenerateCloningCode(printer);
156 GenerateFreezingCode(printer);
157
158 // Fields/properties
159 for (int i = 0; i < descriptor_->field_count(); i++) {
160 const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
161
162 // Rats: we lose the debug comment here :(
163 printer->Print(
164 "/// <summary>Field number for the \"$field_name$\" field.</summary>\n"
165 "public const int $field_constant_name$ = $index$;\n",
166 "field_name", fieldDescriptor->name(),
167 "field_constant_name", GetFieldConstantName(fieldDescriptor),
168 "index", SimpleItoa(fieldDescriptor->number()));
169 scoped_ptr<FieldGeneratorBase> generator(
170 CreateFieldGeneratorInternal(fieldDescriptor));
171 generator->GenerateMembers(printer);
172 printer->Print("\n");
173 }
174
175 // oneof properties
176 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
177 vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
178 vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
179 vars["original_name"] = descriptor_->oneof_decl(i)->name();
180 printer->Print(
181 vars,
182 "private object $name$_;\n"
183 "/// <summary>Enum of possible cases for the \"$original_name$\" oneof.</summary>\n"
184 "public enum $property_name$OneofCase {\n");
185 printer->Indent();
186 printer->Print("None = 0,\n");
187 for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
188 const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
189 printer->Print("$field_property_name$ = $index$,\n",
190 "field_property_name", GetPropertyName(field),
191 "index", SimpleItoa(field->number()));
192 }
193 printer->Outdent();
194 printer->Print("}\n");
195 // TODO: Should we put the oneof .proto comments here?
196 // It's unclear exactly where they should go.
197 printer->Print(
198 vars,
199 "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n");
200 WriteGeneratedCodeAttributes(printer);
201 printer->Print(
202 vars,
203 "public $property_name$OneofCase $property_name$Case {\n"
204 " get { return $name$Case_; }\n"
205 "}\n\n");
206 WriteGeneratedCodeAttributes(printer);
207 printer->Print(
208 vars,
209 "public void Clear$property_name$() {\n"
210 " $name$Case_ = $property_name$OneofCase.None;\n"
211 " $name$_ = null;\n"
212 "}\n\n");
213 }
214
215 // Standard methods
216 GenerateFrameworkMethods(printer);
217 GenerateMessageSerializationMethods(printer);
218 GenerateMergingMethods(printer);
219
220 // Nested messages and enums
221 if (HasNestedGeneratedTypes()) {
222 printer->Print(
223 vars,
224 "#region Nested types\n"
225 "/// <summary>Container for nested types declared in the $class_name$ message type.</summary>\n");
226 WriteGeneratedCodeAttributes(printer);
227 printer->Print("public static partial class Types {\n");
228 printer->Indent();
229 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
230 EnumGenerator enumGenerator(descriptor_->enum_type(i), this->options());
231 enumGenerator.Generate(printer);
232 }
233 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
234 // Don't generate nested types for maps...
235 if (!IsMapEntryMessage(descriptor_->nested_type(i))) {
236 MessageGenerator messageGenerator(
237 descriptor_->nested_type(i), this->options());
238 messageGenerator.Generate(printer);
239 }
240 }
241 printer->Outdent();
242 printer->Print("}\n"
243 "#endregion\n"
244 "\n");
245 }
246
247 printer->Outdent();
248 printer->Print("}\n");
249 printer->Print("\n");
250 }
251
252 // Helper to work out whether we need to generate a class to hold nested types/enums.
253 // Only tricky because we don't want to generate map entry types.
HasNestedGeneratedTypes()254 bool MessageGenerator::HasNestedGeneratedTypes()
255 {
256 if (descriptor_->enum_type_count() > 0) {
257 return true;
258 }
259 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
260 if (!IsMapEntryMessage(descriptor_->nested_type(i))) {
261 return true;
262 }
263 }
264 return false;
265 }
266
GenerateCloningCode(io::Printer * printer)267 void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
268 map<string, string> vars;
269 WriteGeneratedCodeAttributes(printer);
270 vars["class_name"] = class_name();
271 printer->Print(
272 vars,
273 "public $class_name$($class_name$ other) : this() {\n");
274 printer->Indent();
275 // Clone non-oneof fields first
276 for (int i = 0; i < descriptor_->field_count(); i++) {
277 if (!descriptor_->field(i)->containing_oneof()) {
278 scoped_ptr<FieldGeneratorBase> generator(
279 CreateFieldGeneratorInternal(descriptor_->field(i)));
280 generator->GenerateCloningCode(printer);
281 }
282 }
283 // Clone just the right field for each oneof
284 for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
285 vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
286 vars["property_name"] = UnderscoresToCamelCase(
287 descriptor_->oneof_decl(i)->name(), true);
288 printer->Print(vars, "switch (other.$property_name$Case) {\n");
289 printer->Indent();
290 for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
291 const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
292 scoped_ptr<FieldGeneratorBase> generator(CreateFieldGeneratorInternal(field));
293 vars["field_property_name"] = GetPropertyName(field);
294 printer->Print(
295 vars,
296 "case $property_name$OneofCase.$field_property_name$:\n");
297 printer->Indent();
298 generator->GenerateCloningCode(printer);
299 printer->Print("break;\n");
300 printer->Outdent();
301 }
302 printer->Outdent();
303 printer->Print("}\n\n");
304 }
305
306 printer->Outdent();
307 printer->Print("}\n\n");
308
309 WriteGeneratedCodeAttributes(printer);
310 printer->Print(
311 vars,
312 "public $class_name$ Clone() {\n"
313 " return new $class_name$(this);\n"
314 "}\n\n");
315 }
316
GenerateFreezingCode(io::Printer * printer)317 void MessageGenerator::GenerateFreezingCode(io::Printer* printer) {
318 }
319
GenerateFrameworkMethods(io::Printer * printer)320 void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
321 map<string, string> vars;
322 vars["class_name"] = class_name();
323
324 // Equality
325 WriteGeneratedCodeAttributes(printer);
326 printer->Print(
327 vars,
328 "public override bool Equals(object other) {\n"
329 " return Equals(other as $class_name$);\n"
330 "}\n\n");
331 WriteGeneratedCodeAttributes(printer);
332 printer->Print(
333 vars,
334 "public bool Equals($class_name$ other) {\n"
335 " if (ReferenceEquals(other, null)) {\n"
336 " return false;\n"
337 " }\n"
338 " if (ReferenceEquals(other, this)) {\n"
339 " return true;\n"
340 " }\n");
341 printer->Indent();
342 for (int i = 0; i < descriptor_->field_count(); i++) {
343 scoped_ptr<FieldGeneratorBase> generator(
344 CreateFieldGeneratorInternal(descriptor_->field(i)));
345 generator->WriteEquals(printer);
346 }
347 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
348 printer->Print("if ($property_name$Case != other.$property_name$Case) return false;\n",
349 "property_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true));
350 }
351 printer->Outdent();
352 printer->Print(
353 " return true;\n"
354 "}\n\n");
355
356 // GetHashCode
357 // Start with a non-zero value to easily distinguish between null and "empty" messages.
358 WriteGeneratedCodeAttributes(printer);
359 printer->Print(
360 "public override int GetHashCode() {\n"
361 " int hash = 1;\n");
362 printer->Indent();
363 for (int i = 0; i < descriptor_->field_count(); i++) {
364 scoped_ptr<FieldGeneratorBase> generator(
365 CreateFieldGeneratorInternal(descriptor_->field(i)));
366 generator->WriteHash(printer);
367 }
368 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
369 printer->Print("hash ^= (int) $name$Case_;\n",
370 "name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false));
371 }
372 printer->Print("return hash;\n");
373 printer->Outdent();
374 printer->Print("}\n\n");
375
376 WriteGeneratedCodeAttributes(printer);
377 printer->Print(
378 "public override string ToString() {\n"
379 " return pb::JsonFormatter.ToDiagnosticString(this);\n"
380 "}\n\n");
381 }
382
GenerateMessageSerializationMethods(io::Printer * printer)383 void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) {
384 WriteGeneratedCodeAttributes(printer);
385 printer->Print(
386 "public void WriteTo(pb::CodedOutputStream output) {\n");
387 printer->Indent();
388
389 // Serialize all the fields
390 for (int i = 0; i < fields_by_number().size(); i++) {
391 scoped_ptr<FieldGeneratorBase> generator(
392 CreateFieldGeneratorInternal(fields_by_number()[i]));
393 generator->GenerateSerializationCode(printer);
394 }
395
396 // TODO(jonskeet): Memoize size of frozen messages?
397 printer->Outdent();
398 printer->Print(
399 "}\n"
400 "\n");
401 WriteGeneratedCodeAttributes(printer);
402 printer->Print(
403 "public int CalculateSize() {\n");
404 printer->Indent();
405 printer->Print("int size = 0;\n");
406 for (int i = 0; i < descriptor_->field_count(); i++) {
407 scoped_ptr<FieldGeneratorBase> generator(
408 CreateFieldGeneratorInternal(descriptor_->field(i)));
409 generator->GenerateSerializedSizeCode(printer);
410 }
411 printer->Print("return size;\n");
412 printer->Outdent();
413 printer->Print("}\n\n");
414 }
415
GenerateMergingMethods(io::Printer * printer)416 void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
417 // Note: These are separate from GenerateMessageSerializationMethods()
418 // because they need to be generated even for messages that are optimized
419 // for code size.
420 map<string, string> vars;
421 vars["class_name"] = class_name();
422
423 WriteGeneratedCodeAttributes(printer);
424 printer->Print(
425 vars,
426 "public void MergeFrom($class_name$ other) {\n");
427 printer->Indent();
428 printer->Print(
429 "if (other == null) {\n"
430 " return;\n"
431 "}\n");
432 // Merge non-oneof fields
433 for (int i = 0; i < descriptor_->field_count(); i++) {
434 if (!descriptor_->field(i)->containing_oneof()) {
435 scoped_ptr<FieldGeneratorBase> generator(
436 CreateFieldGeneratorInternal(descriptor_->field(i)));
437 generator->GenerateMergingCode(printer);
438 }
439 }
440 // Merge oneof fields
441 for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
442 vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
443 vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
444 printer->Print(vars, "switch (other.$property_name$Case) {\n");
445 printer->Indent();
446 for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
447 const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
448 vars["field_property_name"] = GetPropertyName(field);
449 printer->Print(
450 vars,
451 "case $property_name$OneofCase.$field_property_name$:\n"
452 " $field_property_name$ = other.$field_property_name$;\n"
453 " break;\n");
454 }
455 printer->Outdent();
456 printer->Print("}\n\n");
457 }
458 printer->Outdent();
459 printer->Print("}\n\n");
460 WriteGeneratedCodeAttributes(printer);
461 printer->Print("public void MergeFrom(pb::CodedInputStream input) {\n");
462 printer->Indent();
463 printer->Print(
464 "uint tag;\n"
465 "while ((tag = input.ReadTag()) != 0) {\n"
466 " switch(tag) {\n");
467 printer->Indent();
468 printer->Indent();
469 printer->Print(
470 "default:\n"
471 " input.SkipLastField();\n" // We're not storing the data, but we still need to consume it.
472 " break;\n");
473 for (int i = 0; i < fields_by_number().size(); i++) {
474 const FieldDescriptor* field = fields_by_number()[i];
475 internal::WireFormatLite::WireType wt =
476 internal::WireFormat::WireTypeForFieldType(field->type());
477 uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt);
478 // Handle both packed and unpacked repeated fields with the same Read*Array call;
479 // the two generated cases are the packed and unpacked tags.
480 // TODO(jonskeet): Check that is_packable is equivalent to
481 // is_repeated && wt in { VARINT, FIXED32, FIXED64 }.
482 // It looks like it is...
483 if (field->is_packable()) {
484 printer->Print(
485 "case $packed_tag$:\n",
486 "packed_tag",
487 SimpleItoa(
488 internal::WireFormatLite::MakeTag(
489 field->number(),
490 internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)));
491 }
492
493 printer->Print("case $tag$: {\n", "tag", SimpleItoa(tag));
494 printer->Indent();
495 scoped_ptr<FieldGeneratorBase> generator(
496 CreateFieldGeneratorInternal(field));
497 generator->GenerateParsingCode(printer);
498 printer->Print("break;\n");
499 printer->Outdent();
500 printer->Print("}\n");
501 }
502 printer->Outdent();
503 printer->Print("}\n"); // switch
504 printer->Outdent();
505 printer->Print("}\n"); // while
506 printer->Outdent();
507 printer->Print("}\n\n"); // method
508 }
509
GetFieldOrdinal(const FieldDescriptor * descriptor)510 int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) {
511 for (int i = 0; i < field_names().size(); i++) {
512 if (field_names()[i] == descriptor->name()) {
513 return i;
514 }
515 }
516 GOOGLE_LOG(DFATAL)<< "Could not find ordinal for field " << descriptor->name();
517 return -1;
518 }
519
CreateFieldGeneratorInternal(const FieldDescriptor * descriptor)520 FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal(
521 const FieldDescriptor* descriptor) {
522 return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor), this->options());
523 }
524
525 } // namespace csharp
526 } // namespace compiler
527 } // namespace protobuf
528 } // namespace google
529