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