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