blob: 1defcf94c603c00fc97d2cb46d2c80da5986e636 [file] [log] [blame]
Jan Tattermusch685ae362015-03-16 19:07:16 -07001// 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>
Jie Luo90da3512015-06-03 18:02:17 -070033#include <map>
Jan Tattermusch685ae362015-03-16 19:07:16 -070034
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_enum.h>
Jan Tattermusch685ae362015-03-16 19:07:16 -070046#include <google/protobuf/compiler/csharp/csharp_message.h>
47#include <google/protobuf/compiler/csharp/csharp_helpers.h>
48#include <google/protobuf/compiler/csharp/csharp_field_base.h>
Jan Tattermusch685ae362015-03-16 19:07:16 -070049
50using google::protobuf::internal::scoped_ptr;
51
52namespace google {
53namespace protobuf {
54namespace compiler {
55namespace csharp {
56
57bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) {
58 return d1->number() < d2->number();
59}
60
61MessageGenerator::MessageGenerator(const Descriptor* descriptor)
62 : SourceGeneratorBase(descriptor->file()),
63 descriptor_(descriptor) {
64
65 // sorted field names
66 for (int i = 0; i < descriptor_->field_count(); i++) {
67 field_names_.push_back(descriptor_->field(i)->name());
68 }
69 std::sort(field_names_.begin(), field_names_.end());
70
71 // fields by number
72 for (int i = 0; i < descriptor_->field_count(); i++) {
73 fields_by_number_.push_back(descriptor_->field(i));
74 }
75 std::sort(fields_by_number_.begin(), fields_by_number_.end(),
76 CompareFieldNumbers);
77}
78
79MessageGenerator::~MessageGenerator() {
80}
81
82std::string MessageGenerator::class_name() {
Jan Tattermusch685ae362015-03-16 19:07:16 -070083 return descriptor_->name();
84}
85
86std::string MessageGenerator::full_class_name() {
87 return GetClassName(descriptor_);
88}
89
90const std::vector<std::string>& MessageGenerator::field_names() {
91 return field_names_;
92}
93
94const std::vector<const FieldDescriptor*>& MessageGenerator::fields_by_number() {
95 return fields_by_number_;
96}
97
98/// Get an identifier that uniquely identifies this type within the file.
99/// This is used to declare static variables related to this type at the
100/// outermost file scope.
101std::string GetUniqueFileScopeIdentifier(const Descriptor* descriptor) {
102 std::string result = descriptor->full_name();
103 std::replace(result.begin(), result.end(), '.', '_');
104 return "static_" + result;
105}
106
Jie Luo90da3512015-06-03 18:02:17 -0700107void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
Jon Skeetf5242682015-06-05 20:44:05 +0100108 // Because descriptor.proto (Google.Protobuf.DescriptorProtos) is
Jan Tattermusch685ae362015-03-16 19:07:16 -0700109 // used in the construction of descriptors, we have a tricky bootstrapping
110 // problem. To help control static initialization order, we make sure all
111 // descriptors and other static data that depends on them are members of
112 // the proto-descriptor class. This way, they will be initialized in
113 // a deterministic order.
114
115 std::string identifier = GetUniqueFileScopeIdentifier(descriptor_);
116
Jon Skeetf5242682015-06-05 20:44:05 +0100117 // The descriptor for this type.
118 printer->Print(
119 "internal static pbd::MessageDescriptor internal__$identifier$__Descriptor;\n"
120 "internal static pb::FieldAccess.FieldAccessorTable<$full_class_name$> internal__$identifier$__FieldAccessorTable;\n",
121 "identifier", GetUniqueFileScopeIdentifier(descriptor_),
122 "full_class_name", full_class_name());
Jan Tattermusch685ae362015-03-16 19:07:16 -0700123
124 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
125 MessageGenerator messageGenerator(descriptor_->nested_type(i));
Jie Luo90da3512015-06-03 18:02:17 -0700126 messageGenerator.GenerateStaticVariables(printer);
Jan Tattermusch685ae362015-03-16 19:07:16 -0700127 }
128}
129
Jie Luo90da3512015-06-03 18:02:17 -0700130void MessageGenerator::GenerateStaticVariableInitializers(io::Printer* printer) {
131 map<string, string> vars;
132 vars["identifier"] = GetUniqueFileScopeIdentifier(descriptor_);
133 vars["index"] = SimpleItoa(descriptor_->index());
134 vars["full_class_name"] = full_class_name();
135 if (descriptor_->containing_type() != NULL) {
136 vars["parent"] = GetUniqueFileScopeIdentifier(
137 descriptor_->containing_type());
138 }
Jon Skeetf5242682015-06-05 20:44:05 +0100139 printer->Print(vars, "internal__$identifier$__Descriptor = ");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700140
Jon Skeetf5242682015-06-05 20:44:05 +0100141 if (!descriptor_->containing_type()) {
142 printer->Print(vars, "Descriptor.MessageTypes[$index$];\n");
143 } else {
144 printer->Print(vars, "internal__$parent$__Descriptor.NestedTypes[$index$];\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700145 }
146
Jon Skeetf5242682015-06-05 20:44:05 +0100147 printer->Print(
148 vars,
149 "internal__$identifier$__FieldAccessorTable = \n"
150 " new pb::FieldAccess.FieldAccessorTable<$full_class_name$>(internal__$identifier$__Descriptor,\n");
151 printer->Print(" new string[] { ");
152 for (int i = 0; i < descriptor_->field_count(); i++) {
153 printer->Print("\"$property_name$\", ",
154 "property_name", GetPropertyName(descriptor_->field(i)));
155 }
156 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
157 printer->Print("\"$oneof_name$\", ",
158 "oneof_name",
159 UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true));
160 }
161 printer->Print("});\n");
162
Jan Tattermusch685ae362015-03-16 19:07:16 -0700163 // Generate static member initializers for all nested types.
164 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
165 MessageGenerator messageGenerator(descriptor_->nested_type(i));
Jie Luo90da3512015-06-03 18:02:17 -0700166 messageGenerator.GenerateStaticVariableInitializers(printer);
Jan Tattermusch685ae362015-03-16 19:07:16 -0700167 }
Jan Tattermusch685ae362015-03-16 19:07:16 -0700168}
169
Jie Luo90da3512015-06-03 18:02:17 -0700170void MessageGenerator::Generate(io::Printer* printer) {
171 map<string, string> vars;
172 vars["class_name"] = class_name();
173 vars["access_level"] = class_access_level();
Jie Luo90da3512015-06-03 18:02:17 -0700174 vars["umbrella_class_name"] = GetFullUmbrellaClassName(descriptor_->file());
175 vars["identifier"] = GetUniqueFileScopeIdentifier(descriptor_);
176
177 printer->Print(
Jon Skeetf5242682015-06-05 20:44:05 +0100178 "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
Jie Luo90da3512015-06-03 18:02:17 -0700179 WriteGeneratedCodeAttributes(printer);
180 printer->Print(
181 vars,
Jon Skeetf5242682015-06-05 20:44:05 +0100182 "$access_level$ sealed partial class $class_name$ : pb::IMessage<$class_name$> {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700183 printer->Indent();
Jan Tattermusch685ae362015-03-16 19:07:16 -0700184
Jon Skeetf5242682015-06-05 20:44:05 +0100185 // All static fields and properties
186 printer->Print(
187 "private static readonly string[] _fieldNames = "
188 "new string[] { $slash$$field_names$$slash$ };\n",
189 "field_names", JoinStrings(field_names(), "\", \""),
Jie Luo90da3512015-06-03 18:02:17 -0700190 "slash", field_names().size() > 0 ? "\"" : "");
Jon Skeetf5242682015-06-05 20:44:05 +0100191 std::vector<std::string> tags;
192 for (int i = 0; i < field_names().size(); i++) {
193 uint32 tag = internal::WireFormat::MakeTag(
194 descriptor_->FindFieldByName(field_names()[i]));
195 tags.push_back(SimpleItoa(tag));
Jan Tattermusch685ae362015-03-16 19:07:16 -0700196 }
Jie Luo90da3512015-06-03 18:02:17 -0700197 printer->Print(
Jon Skeetf5242682015-06-05 20:44:05 +0100198 "private static readonly uint[] _fieldTags = new uint[] { $tags$ };\n",
199 "tags", JoinStrings(tags, ", "));
Jie Luo90da3512015-06-03 18:02:17 -0700200
Jon Skeetf5242682015-06-05 20:44:05 +0100201 printer->Print(
202 vars,
203 "public static pbd::MessageDescriptor Descriptor {\n"
204 " get { return $umbrella_class_name$.internal__$identifier$__Descriptor; }\n"
205 "}\n"
206 "\n"
207 "protected override pb::FieldAccess.FieldAccessorTable<$class_name$> InternalFieldAccessors {\n"
208 " get { return $umbrella_class_name$.internal__$identifier$__FieldAccessorTable; }\n"
209 "}\n"
210 "\n");
211
212 // Constructors
213 printer->Print(
214 vars,
215 "public $class_name$() { }\n"); // Public parameterless ctor.
216
217 printer->Print(
218 vars,
219 "public $class_name$($class_name$ other) {\n"
220 " MergeWith(other);\n"
221 "}\n"); // Merge ctor.
222
223 // Fields/properties
224 for (int i = 0; i < descriptor_->field_count(); i++) {
225 const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
226
227 // Rats: we lose the debug comment here :(
228 printer->Print(
229 "public const int $field_constant_name$ = $index$;\n",
230 "field_constant_name", GetFieldConstantName(fieldDescriptor),
231 "index", SimpleItoa(fieldDescriptor->number()));
232 scoped_ptr<FieldGeneratorBase> generator(
233 CreateFieldGeneratorInternal(fieldDescriptor));
234 generator->GenerateMembers(printer);
235 printer->Print("\n");
236 }
237
238 // oneof properties
239 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
240 vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
241 vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
Jie Luo90da3512015-06-03 18:02:17 -0700242 printer->Print(
243 vars,
Jon Skeetf5242682015-06-05 20:44:05 +0100244 "private object $name$_;\n"
245 "public enum $property_name$OneofCase {\n");
246 printer->Indent();
247 printer->Print("None = 0,\n");
248 for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
249 const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
250 printer->Print("$field_property_name$ = $index$,\n",
251 "field_property_name", GetPropertyName(field),
252 "index", SimpleItoa(field->number()));
253 }
254 printer->Outdent();
255 printer->Print("}\n");
256 printer->Print(
257 vars,
258 "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n"
259 "public $property_name$OneofCase $property_name$Case {\n"
260 " get { return $name$Case_; }\n"
261 "}\n\n"
262 "private Clear$property_name$() {;\n"
263 " $name$Case_ = $property_name$OneofCase.None;"
264 " $name$_ = null;"
265 "}\n\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700266 }
267
Jon Skeetf5242682015-06-05 20:44:05 +0100268 // TODO(jonskeet): Map properties
Jan Tattermusch685ae362015-03-16 19:07:16 -0700269
Jon Skeetf5242682015-06-05 20:44:05 +0100270 // Standard methods
271 GenerateMessageSerializationMethods(printer);
272 GenerateMergingMethods(printer);
273
274 // Nested messages and enums
Jan Tattermusch685ae362015-03-16 19:07:16 -0700275 if (descriptor_->enum_type_count() + descriptor_->nested_type_count() > 0) {
Jie Luo90da3512015-06-03 18:02:17 -0700276 printer->Print("#region Nested types\n"
277 "[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]\n");
278 WriteGeneratedCodeAttributes(printer);
279 printer->Print("public static partial class Types {\n");
280 printer->Indent();
Jan Tattermusch685ae362015-03-16 19:07:16 -0700281 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
282 EnumGenerator enumGenerator(descriptor_->enum_type(i));
Jie Luo90da3512015-06-03 18:02:17 -0700283 enumGenerator.Generate(printer);
Jan Tattermusch685ae362015-03-16 19:07:16 -0700284 }
285 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
286 MessageGenerator messageGenerator(descriptor_->nested_type(i));
Jie Luo90da3512015-06-03 18:02:17 -0700287 messageGenerator.Generate(printer);
Jan Tattermusch685ae362015-03-16 19:07:16 -0700288 }
Jie Luo90da3512015-06-03 18:02:17 -0700289 printer->Outdent();
290 printer->Print("}\n"
291 "#endregion\n"
292 "\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700293 }
294
Jie Luo90da3512015-06-03 18:02:17 -0700295 printer->Outdent();
296 printer->Print("}\n");
297 printer->Print("\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700298
299}
300
Jie Luo90da3512015-06-03 18:02:17 -0700301void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer) {
Jie Luo90da3512015-06-03 18:02:17 -0700302 printer->Print(
Jon Skeetf5242682015-06-05 20:44:05 +0100303 "public void WriteTo(pb::ICodedOutputStream output) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700304 printer->Indent();
Jon Skeetf5242682015-06-05 20:44:05 +0100305 printer->Print("string[] fieldNames = _fieldNames;\n");
306
307 // Serialize all the fields
308 for (int i = 0; i < fields_by_number().size(); i++) {
309 scoped_ptr<FieldGeneratorBase> generator(
310 CreateFieldGeneratorInternal(fields_by_number()[i]));
311 generator->GenerateSerializationCode(printer);
Jan Tattermusch685ae362015-03-16 19:07:16 -0700312 }
313
Jon Skeetf5242682015-06-05 20:44:05 +0100314 // TODO(jonskeet): Memoize size of frozen messages?
Jie Luo90da3512015-06-03 18:02:17 -0700315 printer->Outdent();
316 printer->Print(
317 "}\n"
318 "\n"
Jon Skeetf5242682015-06-05 20:44:05 +0100319 "public int CalculateSerializedSize() {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700320 printer->Indent();
Jon Skeetf5242682015-06-05 20:44:05 +0100321 printer->Print("int size = 0;\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700322 for (int i = 0; i < descriptor_->field_count(); i++) {
323 scoped_ptr<FieldGeneratorBase> generator(
324 CreateFieldGeneratorInternal(descriptor_->field(i)));
Jie Luo90da3512015-06-03 18:02:17 -0700325 generator->GenerateSerializedSizeCode(printer);
Jan Tattermusch685ae362015-03-16 19:07:16 -0700326 }
Jon Skeetf5242682015-06-05 20:44:05 +0100327 printer->Print("return size;\n");
Jie Luo90da3512015-06-03 18:02:17 -0700328 printer->Outdent();
329 printer->Print("}\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700330}
331
Jon Skeetf5242682015-06-05 20:44:05 +0100332void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
Jan Tattermusch685ae362015-03-16 19:07:16 -0700333 // Note: These are separate from GenerateMessageSerializationMethods()
334 // because they need to be generated even for messages that are optimized
335 // for code size.
Jie Luo90da3512015-06-03 18:02:17 -0700336 map<string, string> vars;
337 vars["class_name"] = class_name();
Jan Tattermusch685ae362015-03-16 19:07:16 -0700338
Jie Luo90da3512015-06-03 18:02:17 -0700339 printer->Print(
340 vars,
Jon Skeetf5242682015-06-05 20:44:05 +0100341 "public void MergeWith($class_name$ other) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700342 printer->Indent();
343 printer->Print(
Jon Skeetf5242682015-06-05 20:44:05 +0100344 "if (other == null) {\n"
345 " return;\n"
Jie Luo90da3512015-06-03 18:02:17 -0700346 "}\n");
Jon Skeetf5242682015-06-05 20:44:05 +0100347 // TODO(jonskeet): Maps?
348 // Merge non-oneof fields
Jan Tattermusch685ae362015-03-16 19:07:16 -0700349 for (int i = 0; i < descriptor_->field_count(); i++) {
Jon Skeetf5242682015-06-05 20:44:05 +0100350 if (!descriptor_->field(i)->containing_oneof()) {
351 scoped_ptr<FieldGeneratorBase> generator(
352 CreateFieldGeneratorInternal(descriptor_->field(i)));
353 generator->GenerateMergingCode(printer);
354 }
Jan Tattermusch685ae362015-03-16 19:07:16 -0700355 }
Jon Skeetf5242682015-06-05 20:44:05 +0100356 // Merge oneof fields
357 for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) {
358 vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false);
359 vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true);
360 printer->Print(vars, "switch (other.$property_name$Case) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700361 printer->Indent();
Jon Skeetf5242682015-06-05 20:44:05 +0100362 for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) {
363 const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j);
364 vars["field_property_name"] = GetPropertyName(field);
365 printer->Print(
366 vars,
367 "case $property_name$OneofCase.$field_property_name$:\n"
368 " $field_property_name$ = other.$field_property_name$;\n"
369 " break;\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700370 }
Jie Luo90da3512015-06-03 18:02:17 -0700371 printer->Outdent();
372 printer->Print("}\n\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700373 }
Jon Skeetf5242682015-06-05 20:44:05 +0100374 printer->Outdent();
375 printer->Print("}\n\n");
376 printer->Print("public void MergeFrom(pb::ICodedInputStream input) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700377 printer->Indent();
Jie Luo90da3512015-06-03 18:02:17 -0700378 printer->Print(
379 "uint tag;\n"
Jon Skeetf5242682015-06-05 20:44:05 +0100380 "string fieldName;\n"
381 "while (input.ReadTag(out tag, out fieldName)) {\n"
382 " if (tag == 0 && fieldName != null) {");
Jie Luo90da3512015-06-03 18:02:17 -0700383 printer->Indent();
Jie Luo90da3512015-06-03 18:02:17 -0700384 printer->Indent();
Jie Luo90da3512015-06-03 18:02:17 -0700385 printer->Print(
Jon Skeetf5242682015-06-05 20:44:05 +0100386 "int fieldOrdinal = global::System.Array.BinarySearch(_fieldNames, fieldName, global::System.String.String.Ordinal);\n"
387 "if (fieldOrdinal >= 0) {\n"
388 " tag = _fieldTags[fieldOrdinal];\n"
389 "}\n"
390 "switch(tag) {\n");
Jie Luo90da3512015-06-03 18:02:17 -0700391 printer->Indent();
392 printer->Print(
393 "case 0: {\n" // 0 signals EOF / limit reached
394 " throw pb::InvalidProtocolBufferException.InvalidTag();\n"
395 "}\n"
Jon Skeetf5242682015-06-05 20:44:05 +0100396 "default:\n"
397 " if (pb::WireFormat.IsEndGroupTag(tag)) {\n"
398 " return;\n"
399 " }\n"
400 " break;"); // Note: we're ignoring unknown fields here.
Jan Tattermusch685ae362015-03-16 19:07:16 -0700401 for (int i = 0; i < fields_by_number().size(); i++) {
402 const FieldDescriptor* field = fields_by_number()[i];
403 internal::WireFormatLite::WireType wt =
404 internal::WireFormat::WireTypeForFieldType(field->type());
405 uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt);
Jon Skeetf5242682015-06-05 20:44:05 +0100406 // TODO(jonskeet): Understand what this is trying to do
Jan Tattermusch685ae362015-03-16 19:07:16 -0700407 if (field->is_repeated()
408 && (wt == internal::WireFormatLite::WIRETYPE_VARINT
409 || wt == internal::WireFormatLite::WIRETYPE_FIXED32
410 || wt == internal::WireFormatLite::WIRETYPE_FIXED64)) {
Jie Luo90da3512015-06-03 18:02:17 -0700411 printer->Print(
412 "case $number$:\n",
413 "number",
414 SimpleItoa(
415 internal::WireFormatLite::MakeTag(
416 field->number(),
417 internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)));
Jan Tattermusch685ae362015-03-16 19:07:16 -0700418 }
419
Jie Luo90da3512015-06-03 18:02:17 -0700420 printer->Print("case $tag$: {\n", "tag", SimpleItoa(tag));
421 printer->Indent();
Jan Tattermusch685ae362015-03-16 19:07:16 -0700422 scoped_ptr<FieldGeneratorBase> generator(
423 CreateFieldGeneratorInternal(field));
Jie Luo90da3512015-06-03 18:02:17 -0700424 generator->GenerateParsingCode(printer);
425 printer->Print("break;\n");
426 printer->Outdent();
427 printer->Print("}\n");
Jan Tattermusch685ae362015-03-16 19:07:16 -0700428 }
Jie Luo90da3512015-06-03 18:02:17 -0700429 printer->Outdent();
Jon Skeetf5242682015-06-05 20:44:05 +0100430 printer->Print("}\n"); // switch
Jie Luo90da3512015-06-03 18:02:17 -0700431 printer->Outdent();
Jon Skeetf5242682015-06-05 20:44:05 +0100432 printer->Print("}\n"); // if
Jie Luo90da3512015-06-03 18:02:17 -0700433 printer->Outdent();
Jon Skeetf5242682015-06-05 20:44:05 +0100434 printer->Print("}\n"); // while
Jie Luo90da3512015-06-03 18:02:17 -0700435 printer->Outdent();
Jon Skeetf5242682015-06-05 20:44:05 +0100436 printer->Print("}\n\n"); // method
Jan Tattermusch685ae362015-03-16 19:07:16 -0700437}
438
439int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) {
440 for (int i = 0; i < field_names().size(); i++) {
441 if (field_names()[i] == descriptor->name()) {
442 return i;
443 }
444 }
445 GOOGLE_LOG(DFATAL)<< "Could not find ordinal for field " << descriptor->name();
446 return -1;
447}
448
449FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal(
450 const FieldDescriptor* descriptor) {
451 return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor));
452}
453
454} // namespace csharp
455} // namespace compiler
456} // namespace protobuf
457} // namespace google