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