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