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