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::__anonccb115f30111::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::__anonccb115f30111::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::__anonccb115f30111::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 string & root_classname,const Descriptor * descriptor,const Options & options)173 MessageGenerator::MessageGenerator(const 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_(
181 GetOptionalDeprecatedAttribute(descriptor, descriptor->file(), false, true)) {
182
183 for (int i = 0; i < descriptor_->extension_count(); i++) {
184 extension_generators_.emplace_back(
185 new ExtensionGenerator(class_name_, descriptor_->extension(i)));
186 }
187
188 for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) {
189 OneofGenerator* generator = new OneofGenerator(descriptor_->oneof_decl(i));
190 oneof_generators_.emplace_back(generator);
191 }
192
193 for (int i = 0; i < descriptor_->enum_type_count(); i++) {
194 EnumGenerator* generator = new EnumGenerator(descriptor_->enum_type(i));
195 enum_generators_.emplace_back(generator);
196 }
197
198 for (int i = 0; i < descriptor_->nested_type_count(); i++) {
199 MessageGenerator* generator =
200 new MessageGenerator(root_classname_,
201 descriptor_->nested_type(i),
202 options);
203 nested_message_generators_.emplace_back(generator);
204 }
205 }
206
~MessageGenerator()207 MessageGenerator::~MessageGenerator() {}
208
GenerateStaticVariablesInitialization(io::Printer * printer)209 void MessageGenerator::GenerateStaticVariablesInitialization(
210 io::Printer* printer) {
211 for (const auto& generator : extension_generators_) {
212 generator->GenerateStaticVariablesInitialization(printer);
213 }
214
215 for (const auto& generator : nested_message_generators_) {
216 generator->GenerateStaticVariablesInitialization(printer);
217 }
218 }
219
DetermineForwardDeclarations(std::set<string> * fwd_decls)220 void MessageGenerator::DetermineForwardDeclarations(std::set<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<string> * fwd_decls)234 void MessageGenerator::DetermineObjectiveCClassDefinitions(std::set<string>* fwd_decls) {
235 if (!IsMapEntryMessage(descriptor_)) {
236 for (int i = 0; i < descriptor_->field_count(); i++) {
237 const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
238 field_generators_.get(fieldDescriptor)
239 .DetermineObjectiveCClassDefinitions(fwd_decls);
240 }
241 }
242
243 for (const auto& generator : extension_generators_) {
244 generator->DetermineObjectiveCClassDefinitions(fwd_decls);
245 }
246
247 for (const auto& generator : nested_message_generators_) {
248 generator->DetermineObjectiveCClassDefinitions(fwd_decls);
249 }
250
251 const Descriptor* containing_descriptor = descriptor_->containing_type();
252 if (containing_descriptor != NULL) {
253 string containing_class = ClassName(containing_descriptor);
254 fwd_decls->insert(ObjCClassDeclaration(containing_class));
255 }
256 }
257
IncludesOneOfDefinition() const258 bool MessageGenerator::IncludesOneOfDefinition() const {
259 if (!oneof_generators_.empty()) {
260 return true;
261 }
262
263 for (const auto& generator : nested_message_generators_) {
264 if (generator->IncludesOneOfDefinition()) {
265 return true;
266 }
267 }
268
269 return false;
270 }
271
GenerateEnumHeader(io::Printer * printer)272 void MessageGenerator::GenerateEnumHeader(io::Printer* printer) {
273 for (const auto& generator : enum_generators_) {
274 generator->GenerateHeader(printer);
275 }
276
277 for (const auto& generator : nested_message_generators_) {
278 generator->GenerateEnumHeader(printer);
279 }
280 }
281
GenerateExtensionRegistrationSource(io::Printer * printer)282 void MessageGenerator::GenerateExtensionRegistrationSource(
283 io::Printer* printer) {
284 for (const auto& generator : extension_generators_) {
285 generator->GenerateRegistrationSource(printer);
286 }
287
288 for (const auto& generator : nested_message_generators_) {
289 generator->GenerateExtensionRegistrationSource(printer);
290 }
291 }
292
GenerateMessageHeader(io::Printer * printer)293 void MessageGenerator::GenerateMessageHeader(io::Printer* printer) {
294 // This a a map entry message, just recurse and do nothing directly.
295 if (IsMapEntryMessage(descriptor_)) {
296 for (const auto& generator : nested_message_generators_) {
297 generator->GenerateMessageHeader(printer);
298 }
299 return;
300 }
301
302 printer->Print(
303 "#pragma mark - $classname$\n"
304 "\n",
305 "classname", class_name_);
306
307 if (descriptor_->field_count()) {
308 std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
309 SortFieldsByNumber(descriptor_));
310
311 printer->Print("typedef GPB_ENUM($classname$_FieldNumber) {\n",
312 "classname", class_name_);
313 printer->Indent();
314
315 for (int i = 0; i < descriptor_->field_count(); i++) {
316 field_generators_.get(sorted_fields[i])
317 .GenerateFieldNumberConstant(printer);
318 }
319
320 printer->Outdent();
321 printer->Print("};\n\n");
322 }
323
324 for (const auto& generator : oneof_generators_) {
325 generator->GenerateCaseEnum(printer);
326 }
327
328 string message_comments;
329 SourceLocation location;
330 if (descriptor_->GetSourceLocation(&location)) {
331 message_comments = BuildCommentsString(location, false);
332 } else {
333 message_comments = "";
334 }
335
336 printer->Print(
337 "$comments$$deprecated_attribute$GPB_FINAL @interface $classname$ : GPBMessage\n\n",
338 "classname", class_name_,
339 "deprecated_attribute", deprecated_attribute_,
340 "comments", message_comments);
341
342 std::vector<char> seen_oneofs(oneof_generators_.size(), 0);
343 for (int i = 0; i < descriptor_->field_count(); i++) {
344 const FieldDescriptor* field = descriptor_->field(i);
345 const OneofDescriptor *oneof = field->real_containing_oneof();
346 if (oneof) {
347 const int oneof_index = oneof->index();
348 if (!seen_oneofs[oneof_index]) {
349 seen_oneofs[oneof_index] = 1;
350 oneof_generators_[oneof_index]->GeneratePublicCasePropertyDeclaration(
351 printer);
352 }
353 }
354 field_generators_.get(field).GeneratePropertyDeclaration(printer);
355 }
356
357 printer->Print("@end\n\n");
358
359 for (int i = 0; i < descriptor_->field_count(); i++) {
360 field_generators_.get(descriptor_->field(i))
361 .GenerateCFunctionDeclarations(printer);
362 }
363
364 if (!oneof_generators_.empty()) {
365 for (const auto& generator : oneof_generators_) {
366 generator->GenerateClearFunctionDeclaration(printer);
367 }
368 printer->Print("\n");
369 }
370
371 if (descriptor_->extension_count() > 0) {
372 printer->Print("@interface $classname$ (DynamicMethods)\n\n",
373 "classname", class_name_);
374 for (const auto& generator : extension_generators_) {
375 generator->GenerateMembersHeader(printer);
376 }
377 printer->Print("@end\n\n");
378 }
379
380 for (const auto& generator : nested_message_generators_) {
381 generator->GenerateMessageHeader(printer);
382 }
383 }
384
GenerateSource(io::Printer * printer)385 void MessageGenerator::GenerateSource(io::Printer* printer) {
386 if (!IsMapEntryMessage(descriptor_)) {
387 printer->Print(
388 "#pragma mark - $classname$\n"
389 "\n",
390 "classname", class_name_);
391
392 if (!deprecated_attribute_.empty()) {
393 // No warnings when compiling the impl of this deprecated class.
394 printer->Print(
395 "#pragma clang diagnostic push\n"
396 "#pragma clang diagnostic ignored \"-Wdeprecated-implementations\"\n"
397 "\n");
398 }
399
400 printer->Print("@implementation $classname$\n\n",
401 "classname", class_name_);
402
403 for (const auto& generator : oneof_generators_) {
404 generator->GeneratePropertyImplementation(printer);
405 }
406
407 for (int i = 0; i < descriptor_->field_count(); i++) {
408 field_generators_.get(descriptor_->field(i))
409 .GeneratePropertyImplementation(printer);
410 }
411
412 std::unique_ptr<const FieldDescriptor*[]> sorted_fields(
413 SortFieldsByNumber(descriptor_));
414 std::unique_ptr<const FieldDescriptor*[]> size_order_fields(
415 SortFieldsByStorageSize(descriptor_));
416
417 std::vector<const Descriptor::ExtensionRange*> sorted_extensions;
418 sorted_extensions.reserve(descriptor_->extension_range_count());
419 for (int i = 0; i < descriptor_->extension_range_count(); ++i) {
420 sorted_extensions.push_back(descriptor_->extension_range(i));
421 }
422
423 std::sort(sorted_extensions.begin(), sorted_extensions.end(),
424 ExtensionRangeOrdering());
425
426 // Assign has bits:
427 // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing
428 // who needs has bits and assigning them.
429 // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative
430 // index that groups all the elements in the oneof.
431 size_t num_has_bits = field_generators_.CalculateHasBits();
432 size_t sizeof_has_storage = (num_has_bits + 31) / 32;
433 if (sizeof_has_storage == 0) {
434 // In the case where no field needs has bits, don't let the _has_storage_
435 // end up as zero length (zero length arrays are sort of a grey area
436 // since it has to be at the start of the struct). This also ensures a
437 // field with only oneofs keeps the required negative indices they need.
438 sizeof_has_storage = 1;
439 }
440 // Tell all the fields the oneof base.
441 for (const auto& generator : oneof_generators_) {
442 generator->SetOneofIndexBase(sizeof_has_storage);
443 }
444 field_generators_.SetOneofIndexBase(sizeof_has_storage);
445 // sizeof_has_storage needs enough bits for the single fields that aren't in
446 // any oneof, and then one int32 for each oneof (to store the field number).
447 sizeof_has_storage += oneof_generators_.size();
448
449 printer->Print(
450 "\n"
451 "typedef struct $classname$__storage_ {\n"
452 " uint32_t _has_storage_[$sizeof_has_storage$];\n",
453 "classname", class_name_,
454 "sizeof_has_storage", StrCat(sizeof_has_storage));
455 printer->Indent();
456
457 for (int i = 0; i < descriptor_->field_count(); i++) {
458 field_generators_.get(size_order_fields[i])
459 .GenerateFieldStorageDeclaration(printer);
460 }
461 printer->Outdent();
462
463 printer->Print("} $classname$__storage_;\n\n", "classname", class_name_);
464
465
466 printer->Print(
467 "// This method is threadsafe because it is initially called\n"
468 "// in +initialize for each subclass.\n"
469 "+ (GPBDescriptor *)descriptor {\n"
470 " static GPBDescriptor *descriptor = nil;\n"
471 " if (!descriptor) {\n");
472
473 TextFormatDecodeData text_format_decode_data;
474 bool has_fields = descriptor_->field_count() > 0;
475 bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault();
476 string field_description_type;
477 if (need_defaults) {
478 field_description_type = "GPBMessageFieldDescriptionWithDefault";
479 } else {
480 field_description_type = "GPBMessageFieldDescription";
481 }
482 if (has_fields) {
483 printer->Indent();
484 printer->Indent();
485 printer->Print(
486 "static $field_description_type$ fields[] = {\n",
487 "field_description_type", field_description_type);
488 printer->Indent();
489 for (int i = 0; i < descriptor_->field_count(); ++i) {
490 const FieldGenerator& field_generator =
491 field_generators_.get(sorted_fields[i]);
492 field_generator.GenerateFieldDescription(printer, need_defaults);
493 if (field_generator.needs_textformat_name_support()) {
494 text_format_decode_data.AddString(sorted_fields[i]->number(),
495 field_generator.generated_objc_name(),
496 field_generator.raw_field_name());
497 }
498 }
499 printer->Outdent();
500 printer->Print(
501 "};\n");
502 printer->Outdent();
503 printer->Outdent();
504 }
505
506 std::map<string, string> vars;
507 vars["classname"] = class_name_;
508 vars["rootclassname"] = root_classname_;
509 vars["fields"] = has_fields ? "fields" : "NULL";
510 if (has_fields) {
511 vars["fields_count"] =
512 "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))";
513 } else {
514 vars["fields_count"] = "0";
515 }
516
517 std::vector<string> init_flags;
518 init_flags.push_back("GPBDescriptorInitializationFlag_UsesClassRefs");
519 init_flags.push_back("GPBDescriptorInitializationFlag_Proto3OptionalKnown");
520 if (need_defaults) {
521 init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault");
522 }
523 if (descriptor_->options().message_set_wire_format()) {
524 init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat");
525 }
526 vars["init_flags"] = BuildFlagsString(FLAGTYPE_DESCRIPTOR_INITIALIZATION,
527 init_flags);
528
529 printer->Print(
530 vars,
531 " GPBDescriptor *localDescriptor =\n"
532 " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n"
533 " rootClass:[$rootclassname$ class]\n"
534 " file:$rootclassname$_FileDescriptor()\n"
535 " fields:$fields$\n"
536 " fieldCount:$fields_count$\n"
537 " storageSize:sizeof($classname$__storage_)\n"
538 " flags:$init_flags$];\n");
539 if (!oneof_generators_.empty()) {
540 printer->Print(
541 " static const char *oneofs[] = {\n");
542 for (const auto& generator : oneof_generators_) {
543 printer->Print(" \"$name$\",\n", "name",
544 generator->DescriptorName());
545 }
546 printer->Print(
547 " };\n"
548 " [localDescriptor setupOneofs:oneofs\n"
549 " count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n"
550 " firstHasIndex:$first_has_index$];\n",
551 "first_has_index", oneof_generators_[0]->HasIndexAsString());
552 }
553 if (text_format_decode_data.num_entries() != 0) {
554 const string text_format_data_str(text_format_decode_data.Data());
555 printer->Print(
556 "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"
557 " static const char *extraTextFormatInfo =");
558 static const int kBytesPerLine = 40; // allow for escaping
559 for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) {
560 printer->Print(
561 "\n \"$data$\"",
562 "data", EscapeTrigraphs(
563 CEscape(text_format_data_str.substr(i, kBytesPerLine))));
564 }
565 printer->Print(
566 ";\n"
567 " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n"
568 "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n");
569 }
570 if (!sorted_extensions.empty()) {
571 printer->Print(
572 " static const GPBExtensionRange ranges[] = {\n");
573 for (int i = 0; i < sorted_extensions.size(); i++) {
574 printer->Print(" { .start = $start$, .end = $end$ },\n",
575 "start", StrCat(sorted_extensions[i]->start),
576 "end", StrCat(sorted_extensions[i]->end));
577 }
578 printer->Print(
579 " };\n"
580 " [localDescriptor setupExtensionRanges:ranges\n"
581 " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n");
582 }
583 if (descriptor_->containing_type() != NULL) {
584 string containing_class = ClassName(descriptor_->containing_type());
585 string parent_class_ref = ObjCClass(containing_class);
586 printer->Print(
587 " [localDescriptor setupContainingMessageClass:$parent_class_ref$];\n",
588 "parent_class_ref", parent_class_ref);
589 }
590 string suffix_added;
591 ClassName(descriptor_, &suffix_added);
592 if (!suffix_added.empty()) {
593 printer->Print(
594 " [localDescriptor setupMessageClassNameSuffix:@\"$suffix$\"];\n",
595 "suffix", suffix_added);
596 }
597 printer->Print(
598 " #if defined(DEBUG) && DEBUG\n"
599 " NSAssert(descriptor == nil, @\"Startup recursed!\");\n"
600 " #endif // DEBUG\n"
601 " descriptor = localDescriptor;\n"
602 " }\n"
603 " return descriptor;\n"
604 "}\n\n"
605 "@end\n\n");
606
607 if (!deprecated_attribute_.empty()) {
608 printer->Print(
609 "#pragma clang diagnostic pop\n"
610 "\n");
611 }
612
613 for (int i = 0; i < descriptor_->field_count(); i++) {
614 field_generators_.get(descriptor_->field(i))
615 .GenerateCFunctionImplementations(printer);
616 }
617
618 for (const auto& generator : oneof_generators_) {
619 generator->GenerateClearFunctionImplementation(printer);
620 }
621 }
622
623 for (const auto& generator : enum_generators_) {
624 generator->GenerateSource(printer);
625 }
626
627 for (const auto& generator : nested_message_generators_) {
628 generator->GenerateSource(printer);
629 }
630 }
631
632 } // namespace objectivec
633 } // namespace compiler
634 } // namespace protobuf
635 } // namespace google
636