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 <algorithm>
32 #include <iostream>
33 #include <sstream>
34
35 #include <google/protobuf/compiler/objectivec/objectivec_message.h>
36 #include <google/protobuf/compiler/objectivec/objectivec_enum.h>
37 #include <google/protobuf/compiler/objectivec/objectivec_extension.h>
38 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
39 #include <google/protobuf/stubs/stl_util.h>
40 #include <google/protobuf/stubs/strutil.h>
41 #include <google/protobuf/io/printer.h>
42 #include <google/protobuf/io/coded_stream.h>
43 #include <google/protobuf/io/zero_copy_stream_impl.h>
44 #include <google/protobuf/wire_format.h>
45 #include <google/protobuf/wire_format_lite.h>
46 #include <google/protobuf/descriptor.pb.h>
47
48 namespace google {
49 namespace protobuf {
50 namespace compiler {
51 namespace objectivec {
52
53 using internal::WireFormat;
54 using internal::WireFormatLite;
55
56 namespace {
57 struct FieldOrderingByNumber {
operator ()google::protobuf::compiler::objectivec::__anon103f12080111::FieldOrderingByNumber58 inline bool operator()(const FieldDescriptor* a,
59 const FieldDescriptor* b) const {
60 return a->number() < b->number();
61 }
62 };
63
OrderGroupForFieldDescriptor(const FieldDescriptor * descriptor)64 int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) {
65 // The first item in the object structure is our uint32[] for has bits.
66 // We then want to order things to make the instances as small as
67 // possible. So we follow the has bits with:
68 // 1. Anything always 4 bytes - float, *32, enums
69 // 2. Anything that is always a pointer (they will be 8 bytes on 64 bit
70 // builds and 4 bytes on 32bit builds.
71 // 3. Anything always 8 bytes - double, *64
72 //
73 // NOTE: Bools aren't listed, they were stored in the has bits.
74 //
75 // Why? Using 64bit builds as an example, this means worse case, we have
76 // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes
77 // are wasted before the 4 byte values. Then if we have an odd number of
78 // those 4 byte values, the 8 byte values will be pushed down by 32bits to
79 // keep them aligned. But the structure will end 8 byte aligned, so no
80 // waste on the end. If you did the reverse order, you could waste 4 bytes
81 // before the first 8 byte value (after the has array), then a single
82 // bool on the end would need 7 bytes of padding to make the overall
83 // structure 8 byte aligned; so 11 bytes, wasted total.
84
85 // Anything repeated is a GPB*Array/NSArray, so pointer.
86 if (descriptor->is_repeated()) {
87 return 3;
88 }
89
90 switch (descriptor->type()) {
91 // All always 8 bytes.
92 case FieldDescriptor::TYPE_DOUBLE:
93 case FieldDescriptor::TYPE_INT64:
94 case FieldDescriptor::TYPE_SINT64:
95 case FieldDescriptor::TYPE_UINT64:
96 case FieldDescriptor::TYPE_SFIXED64:
97 case FieldDescriptor::TYPE_FIXED64:
98 return 4;
99
100 // Pointers (string and bytes are NSString and NSData); 8 or 4 bytes
101 // depending on the build architecture.
102 case FieldDescriptor::TYPE_GROUP:
103 case FieldDescriptor::TYPE_MESSAGE:
104 case FieldDescriptor::TYPE_STRING:
105 case FieldDescriptor::TYPE_BYTES:
106 return 3;
107
108 // All always 4 bytes (enums are int32s).
109 case FieldDescriptor::TYPE_FLOAT:
110 case FieldDescriptor::TYPE_INT32:
111 case FieldDescriptor::TYPE_SINT32:
112 case FieldDescriptor::TYPE_UINT32:
113 case FieldDescriptor::TYPE_SFIXED32:
114 case FieldDescriptor::TYPE_FIXED32:
115 case FieldDescriptor::TYPE_ENUM:
116 return 2;
117
118 // 0 bytes. Stored in the has bits.
119 case FieldDescriptor::TYPE_BOOL:
120 return 99; // End of the list (doesn't really matter).
121 }
122
123 // Some compilers report reaching end of function even though all cases of
124 // the enum are handed in the switch.
125 GOOGLE_LOG(FATAL) << "Can't get here.";
126 return 0;
127 }
128
129 struct FieldOrderingByStorageSize {
operator ()google::protobuf::compiler::objectivec::__anon103f12080111::FieldOrderingByStorageSize130 inline bool operator()(const FieldDescriptor* a,
131 const FieldDescriptor* b) const {
132 // Order by grouping.
133 const int order_group_a = OrderGroupForFieldDescriptor(a);
134 const int order_group_b = OrderGroupForFieldDescriptor(b);
135 if (order_group_a != order_group_b) {
136 return order_group_a < order_group_b;
137 }
138 // Within the group, order by field number (provides stable ordering).
139 return a->number() < b->number();
140 }
141 };
142
143 struct ExtensionRangeOrdering {
operator ()google::protobuf::compiler::objectivec::__anon103f12080111::ExtensionRangeOrdering144 bool operator()(const Descriptor::ExtensionRange* a,
145 const Descriptor::ExtensionRange* b) const {
146 return a->start < b->start;
147 }
148 };
149
150 // Sort the fields of the given Descriptor by number into a new[]'d array
151 // and return it.
SortFieldsByNumber(const Descriptor * descriptor)152 const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
153 const FieldDescriptor** fields =
154 new const FieldDescriptor* [descriptor->field_count()];
155 for (int i = 0; i < descriptor->field_count(); i++) {
156 fields[i] = descriptor->field(i);
157 }
158 std::sort(fields, fields + descriptor->field_count(), FieldOrderingByNumber());
159 return fields;
160 }
161
162 // Sort the fields of the given Descriptor by storage size into a new[]'d
163 // array and return it.
SortFieldsByStorageSize(const Descriptor * descriptor)164 const FieldDescriptor** SortFieldsByStorageSize(const Descriptor* descriptor) {
165 const FieldDescriptor** fields =
166 new const FieldDescriptor* [descriptor->field_count()];
167 for (int i = 0; i < descriptor->field_count(); i++) {
168 fields[i] = descriptor->field(i);
169 }
170 std::sort(fields, fields + descriptor->field_count(),
171 FieldOrderingByStorageSize());
172 return fields;
173 }
174 } // namespace
175
MessageGenerator(const string & root_classname,const Descriptor * descriptor,const Options & options)176 MessageGenerator::MessageGenerator(const string& root_classname,
177 const Descriptor* descriptor,
178 const Options& options)
179 : root_classname_(root_classname),
180 descriptor_(descriptor),
181 field_generators_(descriptor, options),
182 class_name_(ClassName(descriptor_)),
183 deprecated_attribute_(
184 GetOptionalDeprecatedAttribute(descriptor, descriptor->file(), false, true)) {
185
186 for (int i = 0; i < descriptor_->extension_count(); i++) {
187 extension_generators_.emplace_back(
188 new ExtensionGenerator(class_name_, descriptor_->extension(i)));
189 }
190
191 for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
192 OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i));
193 oneof_generators_.emplace_back(generator);
194 }
195
196 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
197 EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i));
198 enum_generators_.emplace_back(generator);
199 }
200
201 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
202 MessageGenerator* generator =
203 new MessageGenerator(root_classname_,
204 descriptor_->nested_type(i),
205 options);
206 nested_message_generators_.emplace_back(generator);
207 }
208 }
209
~MessageGenerator()210 MessageGenerator::~MessageGenerator() {}
211
GenerateStaticVariablesInitialization(io::Printer * printer)212 void MessageGenerator::GenerateStaticVariablesInitialization(
213 io::Printer* printer) {
214 for (const auto& generator : extension_generators_) {
215 generator->GenerateStaticVariablesInitialization(printer);
216 }
217
218 for (const auto& generator : nested_message_generators_) {
219 generator->GenerateStaticVariablesInitialization(printer);
220 }
221 }
222
DetermineForwardDeclarations(std::set<string> * fwd_decls)223 void MessageGenerator::DetermineForwardDeclarations(std::set<string>* fwd_decls) {
224 if (!IsMapEntryMessage(descriptor_)) {
225 for (int i = 0; i < descriptor_->field_count(); i++) {
226 const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
227 field_generators_.get(fieldDescriptor)
228 .DetermineForwardDeclarations(fwd_decls);
229 }
230 }
231
232 for (const auto& generator : nested_message_generators_) {
233 generator->DetermineForwardDeclarations(fwd_decls);
234 }
235 }
236
IncludesOneOfDefinition() const237 bool MessageGenerator::IncludesOneOfDefinition() const {
238 if (!oneof_generators_.empty()) {
239 return true;
240 }
241
242 for (const auto& generator : nested_message_generators_) {
243 if (generator->IncludesOneOfDefinition()) {
244 return true;
245 }
246 }
247
248 return false;
249 }
250
GenerateEnumHeader(io::Printer * printer)251 void MessageGenerator::GenerateEnumHeader(io::Printer* printer) {
252 for (const auto& generator : enum_generators_) {
253 generator->GenerateHeader(printer);
254 }
255
256 for (const auto& generator : nested_message_generators_) {
257 generator->GenerateEnumHeader(printer);
258 }
259 }
260
GenerateExtensionRegistrationSource(io::Printer * printer)261 void MessageGenerator::GenerateExtensionRegistrationSource(
262 io::Printer* printer) {
263 for (const auto& generator : extension_generators_) {
264 generator->GenerateRegistrationSource(printer);
265 }
266
267 for (const auto& generator : nested_message_generators_) {
268 generator->GenerateExtensionRegistrationSource(printer);
269 }
270 }
271
GenerateMessageHeader(io::Printer * printer)272 void MessageGenerator::GenerateMessageHeader(io::Printer* printer) {
273 // This a a map entry message, just recurse and do nothing directly.
274 if (IsMapEntryMessage(descriptor_)) {
275 for (const auto& generator : nested_message_generators_) {
276 generator->GenerateMessageHeader(printer);
277 }
278 return;
279 }
280
281 printer->Print(
282 "#pragma mark - $classname$\n"
283 "\n",
284 "classname", class_name_);
285
286 if (descriptor_->field_count()) {
287 std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
288 SortFieldsByNumber(descriptor_));
289
290 printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n",
291 "classname", class_name_);
292 printer->Indent();
293
294 for (int i = 0; i < descriptor_->field_count(); i++) {
295 field_generators_.get(sorted_fields[i])
296 .GenerateFieldNumberConstant(printer);
297 }
298
299 printer->Outdent();
300 printer->Print("};\n\n");
301 }
302
303 for (const auto& generator : oneof_generators_) {
304 generator->GenerateCaseEnum(printer);
305 }
306
307 string message_comments;
308 SourceLocation location;
309 if (descriptor_->GetSourceLocation(&location)) {
310 message_comments = BuildCommentsString(location, false);
311 } else {
312 message_comments = "";
313 }
314
315 printer->Print(
316 "$comments$$deprecated_attribute$@interface $classname$ : GPBMessage\n\n",
317 "classname", class_name_,
318 "deprecated_attribute", deprecated_attribute_,
319 "comments", message_comments);
320
321 std::vector<char> seen_oneofs(descriptor_->oneof_decl_count(), 0);
322 for (int i = 0; i < descriptor_->field_count(); i++) {
323 const FieldDescriptor* field = descriptor_->field(i);
324 if (field->containing_oneof() != NULL) {
325 const int oneof_index = field->containing_oneof()->index();
326 if (!seen_oneofs[oneof_index]) {
327 seen_oneofs[oneof_index] = 1;
328 oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration(
329 printer);
330 }
331 }
332 field_generators_.get(field).GeneratePropertyDeclaration(printer);
333 }
334
335 printer->Print("@end\n\n");
336
337 for (int i = 0; i < descriptor_->field_count(); i++) {
338 field_generators_.get(descriptor_->field(i))
339 .GenerateCFunctionDeclarations(printer);
340 }
341
342 if (!oneof_generators_.empty()) {
343 for (const auto& generator : oneof_generators_) {
344 generator->GenerateClearFunctionDeclaration(printer);
345 }
346 printer->Print("\n");
347 }
348
349 if (descriptor_->extension_count() > 0) {
350 printer->Print("@interface $classname$ (DynamicMethods)\n\n",
351 "classname", class_name_);
352 for (const auto& generator : extension_generators_) {
353 generator->GenerateMembersHeader(printer);
354 }
355 printer->Print("@end\n\n");
356 }
357
358 for (const auto& generator : nested_message_generators_) {
359 generator->GenerateMessageHeader(printer);
360 }
361 }
362
GenerateSource(io::Printer * printer)363 void MessageGenerator::GenerateSource(io::Printer* printer) {
364 if (!IsMapEntryMessage(descriptor_)) {
365 printer->Print(
366 "#pragma mark - $classname$\n"
367 "\n",
368 "classname", class_name_);
369
370 if (!deprecated_attribute_.empty()) {
371 // No warnings when compiling the impl of this deprecated class.
372 printer->Print(
373 "#pragma clang diagnostic push\n"
374 "#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n"
375 "\n");
376 }
377
378 printer->Print("@implementation $classname$\n\n",
379 "classname", class_name_);
380
381 for (const auto& generator : oneof_generators_) {
382 generator->GeneratePropertyImplementation(printer);
383 }
384
385 for (int i = 0; i < descriptor_->field_count(); i++) {
386 field_generators_.get(descriptor_->field(i))
387 .GeneratePropertyImplementation(printer);
388 }
389
390 std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
391 SortFieldsByNumber(descriptor_));
392 std::unique_ptr<const FieldDescriptor*[]> size_order_fields(
393 SortFieldsByStorageSize(descriptor_));
394
395 std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
396 for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
397 sorted_extensions.push_back(descriptor_->extension_range(i));
398 }
399
400 std::sort(sorted_extensions.begin(), sorted_extensions.end(),
401 ExtensionRangeOrdering());
402
403 // Assign has bits:
404 // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing
405 // who needs has bits and assigning them.
406 // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
407 // index that groups all the elements in the oneof.
408 size_t num_has_bits = field_generators_.CalculateHasBits();
409 size_t sizeof_has_storage = (num_has_bits + 31) / 32;
410 if (sizeof_has_storage == 0) {
411 // In the case where no field needs has bits, don't let the _has_storage_
412 // end up as zero length (zero length arrays are sort of a grey area
413 // since it has to be at the start of the struct). This also ensures a
414 // field with only oneofs keeps the required negative indices they need.
415 sizeof_has_storage = 1;
416 }
417 // Tell all the fields the oneof base.
418 for (const auto& generator : oneof_generators_) {
419 generator->SetOneofIndexBase(sizeof_has_storage);
420 }
421 field_generators_.SetOneofIndexBase(sizeof_has_storage);
422 // sizeof_has_storage needs enough bits for the single fields that aren't in
423 // any oneof, and then one int32 for each oneof (to store the field number).
424 sizeof_has_storage += descriptor_->oneof_decl_count();
425
426 printer->Print(
427 "\n"
428 "typedef struct $classname$__storage_ {\n"
429 " uint32_t _has_storage_[$sizeof_has_storage$];\n",
430 "classname", class_name_,
431 "sizeof_has_storage", StrCat(sizeof_has_storage));
432 printer->Indent();
433
434 for (int i = 0; i < descriptor_->field_count(); i++) {
435 field_generators_.get(size_order_fields[i])
436 .GenerateFieldStorageDeclaration(printer);
437 }
438 printer->Outdent();
439
440 printer->Print("} $classname$__storage_;\n\n", "classname", class_name_);
441
442
443 printer->Print(
444 "// This method is threadsafe because it is initially called\n"
445 "// in +initialize for each subclass.\n"
446 "+ (GPBDescriptor *)descriptor {\n"
447 " static GPBDescriptor *descriptor = nil;\n"
448 " if (!descriptor) {\n");
449
450 TextFormatDecodeData text_format_decode_data;
451 bool has_fields = descriptor_->field_count() > 0;
452 bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault();
453 string field_description_type;
454 if (need_defaults) {
455 field_description_type = "GPBMessageFieldDescriptionWithDefault";
456 } else {
457 field_description_type = "GPBMessageFieldDescription";
458 }
459 if (has_fields) {
460 printer->Print(
461 " static $field_description_type$ fields[] = {\n",
462 "field_description_type", field_description_type);
463 printer->Indent();
464 printer->Indent();
465 printer->Indent();
466 for (int i = 0; i < descriptor_->field_count(); ++i) {
467 const FieldGenerator& field_generator =
468 field_generators_.get(sorted_fields[i]);
469 field_generator.GenerateFieldDescription(printer, need_defaults);
470 if (field_generator.needs_textformat_name_support()) {
471 text_format_decode_data.AddString(sorted_fields[i]->number(),
472 field_generator.generated_objc_name(),
473 field_generator.raw_field_name());
474 }
475 }
476 printer->Outdent();
477 printer->Outdent();
478 printer->Outdent();
479 printer->Print(
480 " };\n");
481 }
482
483 std::map<string, string> vars;
484 vars["classname"] = class_name_;
485 vars["rootclassname"] = root_classname_;
486 vars["fields"] = has_fields ? "fields" : "NULL";
487 if (has_fields) {
488 vars["fields_count"] =
489 "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))";
490 } else {
491 vars["fields_count"] = "0";
492 }
493
494 std::vector<string> init_flags;
495 if (need_defaults) {
496 init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault");
497 }
498 if (descriptor_->options().message_set_wire_format()) {
499 init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat");
500 }
501 vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION,
502 init_flags);
503
504 printer->Print(
505 vars,
506 " GPBDescriptor *localDescriptor =\n"
507 " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
508 " rootClass:[$rootclassname$ class]\n"
509 " file:$rootclassname$_FileDescriptor()\n"
510 " fields:$fields$\n"
511 " fieldCount:$fields_count$\n"
512 " storageSize:sizeof($classname$__storage_)\n"
513 " flags:$init_flags$];\n");
514 if (oneof_generators_.size() != 0) {
515 printer->Print(
516 " static const char *oneofs[] = {\n");
517 for (const auto& generator : oneof_generators_) {
518 printer->Print(" \"$name$\",\n", "name",
519 generator->DescriptorName());
520 }
521 printer->Print(
522 " };\n"
523 " [localDescriptor setupOneofs:oneofs\n"
524 " count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n"
525 " firstHasIndex:$first_has_index$];\n",
526 "first_has_index", oneof_generators_[0]->HasIndexAsString());
527 }
528 if (text_format_decode_data.num_entries() != 0) {
529 const string text_format_data_str(text_format_decode_data.Data());
530 printer->Print(
531 "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
532 " static const char *extraTextFormatInfo =");
533 static const int kBytesPerLine = 40; // allow for escaping
534 for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) {
535 printer->Print(
536 "\n \"$data$\"",
537 "data", EscapeTrigraphs(
538 CEscape(text_format_data_str.substr(i, kBytesPerLine))));
539 }
540 printer->Print(
541 ";\n"
542 " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n"
543 "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n");
544 }
545 if (sorted_extensions.size() != 0) {
546 printer->Print(
547 " static const GPBExtensionRange ranges[] = {\n");
548 for (int i = 0; i < sorted_extensions.size(); i++) {
549 printer->Print(" { .start = $start$, .end = $end$ },\n",
550 "start", StrCat(sorted_extensions[i]->start),
551 "end", StrCat(sorted_extensions[i]->end));
552 }
553 printer->Print(
554 " };\n"
555 " [localDescriptor setupExtensionRanges:ranges\n"
556 " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
557 }
558 if (descriptor_->containing_type() != NULL) {
559 string parent_class_name = ClassName(descriptor_->containing_type());
560 printer->Print(
561 " [localDescriptor setupContainingMessageClassName:GPBStringifySymbol($parent_name$)];\n",
562 "parent_name", parent_class_name);
563 }
564 string suffix_added;
565 ClassName(descriptor_, &suffix_added);
566 if (suffix_added.size() > 0) {
567 printer->Print(
568 " [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n",
569 "suffix", suffix_added);
570 }
571 printer->Print(
572 " #if defined(DEBUG) && DEBUG\n"
573 " NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
574 " #endif // DEBUG\n"
575 " descriptor = localDescriptor;\n"
576 " }\n"
577 " return descriptor;\n"
578 "}\n\n"
579 "@end\n\n");
580
581 if (!deprecated_attribute_.empty()) {
582 printer->Print(
583 "#pragma clang diagnostic pop\n"
584 "\n");
585 }
586
587 for (int i = 0; i < descriptor_->field_count(); i++) {
588 field_generators_.get(descriptor_->field(i))
589 .GenerateCFunctionImplementations(printer);
590 }
591
592 for (const auto& generator : oneof_generators_) {
593 generator->GenerateClearFunctionImplementation(printer);
594 }
595 }
596
597 for (const auto& generator : enum_generators_) {
598 generator->GenerateSource(printer);
599 }
600
601 for (const auto& generator : nested_message_generators_) {
602 generator->GenerateSource(printer);
603 }
604 }
605
606 } // namespace objectivec
607 } // namespace compiler
608 } // namespace protobuf
609 } // namespace google
610