• 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 <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