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 <google/protobuf/compiler/objectivec/objectivec_file.h>
32 #include <google/protobuf/compiler/objectivec/objectivec_enum.h>
33 #include <google/protobuf/compiler/objectivec/objectivec_extension.h>
34 #include <google/protobuf/compiler/objectivec/objectivec_helpers.h>
35 #include <google/protobuf/compiler/objectivec/objectivec_message.h>
36 #include <google/protobuf/compiler/code_generator.h>
37 #include <google/protobuf/io/printer.h>
38 #include <google/protobuf/io/zero_copy_stream_impl.h>
39 #include <google/protobuf/stubs/stl_util.h>
40 #include <google/protobuf/stubs/strutil.h>
41 #include <algorithm> // std::find()
42 #include <iostream>
43 #include <sstream>
44
45 // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some
46 // error cases, so it seems to be ok to use as a back door for errors.
47
48 namespace google {
49 namespace protobuf {
50 namespace compiler {
51 namespace objectivec {
52
53 namespace {
54
55 // This is also found in GPBBootstrap.h, and needs to be kept in sync.
56 const int32_t GOOGLE_PROTOBUF_OBJC_VERSION = 30004;
57
58 const char* kHeaderExtension = ".pbobjc.h";
59
BundledFileName(const FileDescriptor * file)60 std::string BundledFileName(const FileDescriptor* file) {
61 return "GPB" + FilePathBasename(file) + kHeaderExtension;
62 }
63
64 // Checks if a message contains any enums definitions (on the message or
65 // a nested message under it).
MessageContainsEnums(const Descriptor * message)66 bool MessageContainsEnums(const Descriptor* message) {
67 if (message->enum_type_count() > 0) {
68 return true;
69 }
70 for (int i = 0; i < message->nested_type_count(); i++) {
71 if (MessageContainsEnums(message->nested_type(i))) {
72 return true;
73 }
74 }
75 return false;
76 }
77
78 // Checks if a message contains any extension definitions (on the message or
79 // a nested message under it).
MessageContainsExtensions(const Descriptor * message)80 bool MessageContainsExtensions(const Descriptor* message) {
81 if (message->extension_count() > 0) {
82 return true;
83 }
84 for (int i = 0; i < message->nested_type_count(); i++) {
85 if (MessageContainsExtensions(message->nested_type(i))) {
86 return true;
87 }
88 }
89 return false;
90 }
91
92 // Checks if the file contains any enum definitions (at the root or
93 // nested under a message).
FileContainsEnums(const FileDescriptor * file)94 bool FileContainsEnums(const FileDescriptor* file) {
95 if (file->enum_type_count() > 0) {
96 return true;
97 }
98 for (int i = 0; i < file->message_type_count(); i++) {
99 if (MessageContainsEnums(file->message_type(i))) {
100 return true;
101 }
102 }
103 return false;
104 }
105
106 // Checks if the file contains any extensions definitions (at the root or
107 // nested under a message).
FileContainsExtensions(const FileDescriptor * file)108 bool FileContainsExtensions(const FileDescriptor* file) {
109 if (file->extension_count() > 0) {
110 return true;
111 }
112 for (int i = 0; i < file->message_type_count(); i++) {
113 if (MessageContainsExtensions(file->message_type(i))) {
114 return true;
115 }
116 }
117 return false;
118 }
119
120 // Helper for CollectMinimalFileDepsContainingExtensionsWorker that marks all
121 // deps as visited and prunes them from the needed files list.
PruneFileAndDepsMarkingAsVisited(const FileDescriptor * file,std::vector<const FileDescriptor * > * files,std::set<const FileDescriptor * > * files_visited)122 void PruneFileAndDepsMarkingAsVisited(
123 const FileDescriptor* file,
124 std::vector<const FileDescriptor*>* files,
125 std::set<const FileDescriptor*>* files_visited) {
126 std::vector<const FileDescriptor*>::iterator iter =
127 std::find(files->begin(), files->end(), file);
128 if (iter != files->end()) {
129 files->erase(iter);
130 }
131 files_visited->insert(file);
132 for (int i = 0; i < file->dependency_count(); i++) {
133 PruneFileAndDepsMarkingAsVisited(file->dependency(i), files, files_visited);
134 }
135 }
136
137 // Helper for CollectMinimalFileDepsContainingExtensions.
CollectMinimalFileDepsContainingExtensionsWorker(const FileDescriptor * file,std::vector<const FileDescriptor * > * files,std::set<const FileDescriptor * > * files_visited)138 void CollectMinimalFileDepsContainingExtensionsWorker(
139 const FileDescriptor* file,
140 std::vector<const FileDescriptor*>* files,
141 std::set<const FileDescriptor*>* files_visited) {
142 if (files_visited->find(file) != files_visited->end()) {
143 return;
144 }
145 files_visited->insert(file);
146
147 if (FileContainsExtensions(file)) {
148 files->push_back(file);
149 for (int i = 0; i < file->dependency_count(); i++) {
150 const FileDescriptor* dep = file->dependency(i);
151 PruneFileAndDepsMarkingAsVisited(dep, files, files_visited);
152 }
153 } else {
154 for (int i = 0; i < file->dependency_count(); i++) {
155 const FileDescriptor* dep = file->dependency(i);
156 CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
157 files_visited);
158 }
159 }
160 }
161
162 // Collect the deps of the given file that contain extensions. This can be used to
163 // create the chain of roots that need to be wired together.
164 //
165 // NOTE: If any changes are made to this and the supporting functions, you will
166 // need to manually validate what the generated code is for the test files:
167 // objectivec/Tests/unittest_extension_chain_*.proto
168 // There are comments about what the expected code should be line and limited
169 // testing objectivec/Tests/GPBUnittestProtos2.m around compilation (#imports
170 // specifically).
CollectMinimalFileDepsContainingExtensions(const FileDescriptor * file,std::vector<const FileDescriptor * > * files)171 void CollectMinimalFileDepsContainingExtensions(
172 const FileDescriptor* file,
173 std::vector<const FileDescriptor*>* files) {
174 std::set<const FileDescriptor*> files_visited;
175 for (int i = 0; i < file->dependency_count(); i++) {
176 const FileDescriptor* dep = file->dependency(i);
177 CollectMinimalFileDepsContainingExtensionsWorker(dep, files,
178 &files_visited);
179 }
180 }
181
IsDirectDependency(const FileDescriptor * dep,const FileDescriptor * file)182 bool IsDirectDependency(const FileDescriptor* dep, const FileDescriptor* file) {
183 for (int i = 0; i < file->dependency_count(); i++) {
184 if (dep == file->dependency(i)) {
185 return true;
186 }
187 }
188 return false;
189 }
190
191 } // namespace
192
FileGenerator(const FileDescriptor * file,const GenerationOptions & generation_options)193 FileGenerator::FileGenerator(const FileDescriptor* file,
194 const GenerationOptions& generation_options)
195 : file_(file),
196 generation_options_(generation_options),
197 root_class_name_(FileClassName(file)),
198 is_bundled_proto_(IsProtobufLibraryBundledProtoFile(file)) {
199 for (int i = 0; i < file_->enum_type_count(); i++) {
200 EnumGenerator* generator = new EnumGenerator(file_->enum_type(i));
201 enum_generators_.emplace_back(generator);
202 }
203 for (int i = 0; i < file_->message_type_count(); i++) {
204 MessageGenerator* generator =
205 new MessageGenerator(root_class_name_, file_->message_type(i));
206 message_generators_.emplace_back(generator);
207 }
208 for (int i = 0; i < file_->extension_count(); i++) {
209 ExtensionGenerator* generator =
210 new ExtensionGenerator(root_class_name_, file_->extension(i));
211 extension_generators_.emplace_back(generator);
212 }
213 }
214
~FileGenerator()215 FileGenerator::~FileGenerator() {}
216
GenerateHeader(io::Printer * printer)217 void FileGenerator::GenerateHeader(io::Printer* printer) {
218 std::vector<std::string> headers;
219 // Generated files bundled with the library get minimal imports, everything
220 // else gets the wrapper so everything is usable.
221 if (is_bundled_proto_) {
222 headers.push_back("GPBDescriptor.h");
223 headers.push_back("GPBMessage.h");
224 headers.push_back("GPBRootObject.h");
225 for (int i = 0; i < file_->dependency_count(); i++) {
226 const std::string header_name = BundledFileName(file_->dependency(i));
227 headers.push_back(header_name);
228 }
229 } else {
230 headers.push_back("GPBProtocolBuffers.h");
231 }
232 PrintFileRuntimePreamble(printer, headers);
233
234 // Add some verification that the generated code matches the source the
235 // code is being compiled with.
236 // NOTE: This captures the raw numeric values at the time the generator was
237 // compiled, since that will be the versions for the ObjC runtime at that
238 // time. The constants in the generated code will then get their values at
239 // at compile time (so checking against the headers being used to compile).
240 printer->Print(
241 "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n"
242 "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n"
243 "#endif\n"
244 "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n"
245 "#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n"
246 "#endif\n"
247 "\n",
248 "google_protobuf_objc_version", StrCat(GOOGLE_PROTOBUF_OBJC_VERSION));
249
250 // The bundled protos (WKTs) don't use of forward declarations.
251 bool headers_use_forward_declarations =
252 generation_options_.headers_use_forward_declarations && !is_bundled_proto_;
253
254 {
255 ImportWriter import_writer(
256 generation_options_.generate_for_named_framework,
257 generation_options_.named_framework_to_proto_path_mappings_path,
258 generation_options_.runtime_import_prefix,
259 /* include_wkt_imports = */ false);
260 const std::string header_extension(kHeaderExtension);
261 if (headers_use_forward_declarations) {
262 // #import any headers for "public imports" in the proto file.
263 for (int i = 0; i < file_->public_dependency_count(); i++) {
264 import_writer.AddFile(file_->public_dependency(i), header_extension);
265 }
266 } else {
267 for (int i = 0; i < file_->dependency_count(); i++) {
268 import_writer.AddFile(file_->dependency(i), header_extension);
269 }
270 }
271 import_writer.Print(printer);
272 }
273
274 // Note:
275 // deprecated-declarations suppression is only needed if some place in this
276 // proto file is something deprecated or if it references something from
277 // another file that is deprecated.
278 printer->Print(
279 "// @@protoc_insertion_point(imports)\n"
280 "\n"
281 "#pragma clang diagnostic push\n"
282 "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
283 "\n"
284 "CF_EXTERN_C_BEGIN\n"
285 "\n");
286
287 std::set<std::string> fwd_decls;
288 for (const auto& generator : message_generators_) {
289 generator->DetermineForwardDeclarations(
290 &fwd_decls,
291 /* include_external_types = */ headers_use_forward_declarations);
292 }
293 for (std::set<std::string>::const_iterator i(fwd_decls.begin());
294 i != fwd_decls.end(); ++i) {
295 printer->Print("$value$;\n", "value", *i);
296 }
297 if (fwd_decls.begin() != fwd_decls.end()) {
298 printer->Print("\n");
299 }
300
301 printer->Print(
302 "NS_ASSUME_NONNULL_BEGIN\n"
303 "\n");
304
305 // need to write out all enums first
306 for (const auto& generator : enum_generators_) {
307 generator->GenerateHeader(printer);
308 }
309
310 for (const auto& generator : message_generators_) {
311 generator->GenerateEnumHeader(printer);
312 }
313
314 // For extensions to chain together, the Root gets created even if there
315 // are no extensions.
316 printer->Print(
317 "#pragma mark - $root_class_name$\n"
318 "\n"
319 "/**\n"
320 " * Exposes the extension registry for this file.\n"
321 " *\n"
322 " * The base class provides:\n"
323 " * @code\n"
324 " * + (GPBExtensionRegistry *)extensionRegistry;\n"
325 " * @endcode\n"
326 " * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n"
327 " * this file and all files that it depends on.\n"
328 " **/\n"
329 "GPB_FINAL @interface $root_class_name$ : GPBRootObject\n"
330 "@end\n"
331 "\n",
332 "root_class_name", root_class_name_);
333
334 if (!extension_generators_.empty()) {
335 // The dynamic methods block is only needed if there are extensions.
336 printer->Print(
337 "@interface $root_class_name$ (DynamicMethods)\n",
338 "root_class_name", root_class_name_);
339
340 for (const auto& generator : extension_generators_) {
341 generator->GenerateMembersHeader(printer);
342 }
343
344 printer->Print("@end\n\n");
345 } // !extension_generators_.empty()
346
347 for (const auto& generator : message_generators_) {
348 generator->GenerateMessageHeader(printer);
349 }
350
351 printer->Print(
352 "NS_ASSUME_NONNULL_END\n"
353 "\n"
354 "CF_EXTERN_C_END\n"
355 "\n"
356 "#pragma clang diagnostic pop\n"
357 "\n"
358 "// @@protoc_insertion_point(global_scope)\n");
359 }
360
GenerateSource(io::Printer * printer)361 void FileGenerator::GenerateSource(io::Printer* printer) {
362 // #import the runtime support.
363 std::vector<std::string> headers;
364 headers.push_back("GPBProtocolBuffers_RuntimeSupport.h");
365 if (is_bundled_proto_) {
366 headers.push_back(BundledFileName(file_));
367 }
368 PrintFileRuntimePreamble(printer, headers);
369
370 // Enums use atomic in the generated code, so add the system import as needed.
371 if (FileContainsEnums(file_)) {
372 printer->Print(
373 "#import <stdatomic.h>\n"
374 "\n");
375 }
376
377 std::vector<const FileDescriptor*> deps_with_extensions;
378 CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions);
379
380 // The bundled protos (WKTs) don't use of forward declarations.
381 bool headers_use_forward_declarations =
382 generation_options_.headers_use_forward_declarations && !is_bundled_proto_;
383
384 {
385 ImportWriter import_writer(
386 generation_options_.generate_for_named_framework,
387 generation_options_.named_framework_to_proto_path_mappings_path,
388 generation_options_.runtime_import_prefix,
389 /* include_wkt_imports = */ false);
390 const std::string header_extension(kHeaderExtension);
391
392 // #import the header for this proto file.
393 import_writer.AddFile(file_, header_extension);
394
395 if (headers_use_forward_declarations) {
396 // #import the headers for anything that a plain dependency of this proto
397 // file (that means they were just an include, not a "public" include).
398 std::set<std::string> public_import_names;
399 for (int i = 0; i < file_->public_dependency_count(); i++) {
400 public_import_names.insert(file_->public_dependency(i)->name());
401 }
402 for (int i = 0; i < file_->dependency_count(); i++) {
403 const FileDescriptor *dep = file_->dependency(i);
404 bool public_import = (public_import_names.count(dep->name()) != 0);
405 if (!public_import) {
406 import_writer.AddFile(dep, header_extension);
407 }
408 }
409 }
410
411 // If any indirect dependency provided extensions, it needs to be directly
412 // imported so it can get merged into the root's extensions registry.
413 // See the Note by CollectMinimalFileDepsContainingExtensions before
414 // changing this.
415 for (std::vector<const FileDescriptor*>::iterator iter =
416 deps_with_extensions.begin();
417 iter != deps_with_extensions.end(); ++iter) {
418 if (!IsDirectDependency(*iter, file_)) {
419 import_writer.AddFile(*iter, header_extension);
420 }
421 }
422
423 import_writer.Print(printer);
424 }
425
426 bool includes_oneof = false;
427 for (const auto& generator : message_generators_) {
428 if (generator->IncludesOneOfDefinition()) {
429 includes_oneof = true;
430 break;
431 }
432 }
433
434 std::set<std::string> fwd_decls;
435 for (const auto& generator : message_generators_) {
436 generator->DetermineObjectiveCClassDefinitions(&fwd_decls);
437 }
438 for (const auto& generator : extension_generators_) {
439 generator->DetermineObjectiveCClassDefinitions(&fwd_decls);
440 }
441
442 // Note:
443 // deprecated-declarations suppression is only needed if some place in this
444 // proto file is something deprecated or if it references something from
445 // another file that is deprecated.
446 // dollar-in-identifier-extension is needed because we use references to
447 // objc class names that have $ in identifiers.
448 printer->Print(
449 "// @@protoc_insertion_point(imports)\n"
450 "\n"
451 "#pragma clang diagnostic push\n"
452 "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n");
453 if (includes_oneof) {
454 // The generated code for oneof's uses direct ivar access, suppress the
455 // warning in case developer turn that on in the context they compile the
456 // generated code.
457 printer->Print(
458 "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n");
459 }
460 if (!fwd_decls.empty()) {
461 printer->Print(
462 "#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n");
463 }
464 printer->Print(
465 "\n");
466 if (!fwd_decls.empty()) {
467 printer->Print(
468 "#pragma mark - Objective C Class declarations\n"
469 "// Forward declarations of Objective C classes that we can use as\n"
470 "// static values in struct initializers.\n"
471 "// We don't use [Foo class] because it is not a static value.\n");
472 }
473 for (const auto& i : fwd_decls) {
474 printer->Print("$value$\n", "value", i);
475 }
476 if (!fwd_decls.empty()) {
477 printer->Print("\n");
478 }
479 printer->Print(
480 "#pragma mark - $root_class_name$\n"
481 "\n"
482 "@implementation $root_class_name$\n\n",
483 "root_class_name", root_class_name_);
484
485 const bool file_contains_extensions = FileContainsExtensions(file_);
486
487 // If there were any extensions or this file has any dependencies, output
488 // a registry to override to create the file specific registry.
489 if (file_contains_extensions || !deps_with_extensions.empty()) {
490 printer->Print(
491 "+ (GPBExtensionRegistry*)extensionRegistry {\n"
492 " // This is called by +initialize so there is no need to worry\n"
493 " // about thread safety and initialization of registry.\n"
494 " static GPBExtensionRegistry* registry = nil;\n"
495 " if (!registry) {\n"
496 " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"
497 " registry = [[GPBExtensionRegistry alloc] init];\n");
498
499 printer->Indent();
500 printer->Indent();
501
502 if (file_contains_extensions) {
503 printer->Print(
504 "static GPBExtensionDescription descriptions[] = {\n");
505 printer->Indent();
506 for (const auto& generator : extension_generators_) {
507 generator->GenerateStaticVariablesInitialization(printer);
508 }
509 for (const auto& generator : message_generators_) {
510 generator->GenerateStaticVariablesInitialization(printer);
511 }
512 printer->Outdent();
513 printer->Print(
514 "};\n"
515 "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n"
516 " GPBExtensionDescriptor *extension =\n"
517 " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]\n"
518 " usesClassRefs:YES];\n"
519 " [registry addExtension:extension];\n"
520 " [self globallyRegisterExtension:extension];\n"
521 " [extension release];\n"
522 "}\n");
523 }
524
525 if (deps_with_extensions.empty()) {
526 printer->Print(
527 "// None of the imports (direct or indirect) defined extensions, so no need to add\n"
528 "// them to this registry.\n");
529 } else {
530 printer->Print(
531 "// Merge in the imports (direct or indirect) that defined extensions.\n");
532 for (std::vector<const FileDescriptor*>::iterator iter =
533 deps_with_extensions.begin();
534 iter != deps_with_extensions.end(); ++iter) {
535 const std::string root_class_name(FileClassName((*iter)));
536 printer->Print(
537 "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
538 "dependency", root_class_name);
539 }
540 }
541
542 printer->Outdent();
543 printer->Outdent();
544
545 printer->Print(
546 " }\n"
547 " return registry;\n"
548 "}\n");
549 } else {
550 if (file_->dependency_count() > 0) {
551 printer->Print(
552 "// No extensions in the file and none of the imports (direct or indirect)\n"
553 "// defined extensions, so no need to generate +extensionRegistry.\n");
554 } else {
555 printer->Print(
556 "// No extensions in the file and no imports, so no need to generate\n"
557 "// +extensionRegistry.\n");
558 }
559 }
560
561 printer->Print("\n@end\n\n");
562
563 // File descriptor only needed if there are messages to use it.
564 if (!message_generators_.empty()) {
565 std::map<std::string, std::string> vars;
566 vars["root_class_name"] = root_class_name_;
567 vars["package"] = file_->package();
568 vars["objc_prefix"] = FileClassPrefix(file_);
569 switch (file_->syntax()) {
570 case FileDescriptor::SYNTAX_UNKNOWN:
571 vars["syntax"] = "GPBFileSyntaxUnknown";
572 break;
573 case FileDescriptor::SYNTAX_PROTO2:
574 vars["syntax"] = "GPBFileSyntaxProto2";
575 break;
576 case FileDescriptor::SYNTAX_PROTO3:
577 vars["syntax"] = "GPBFileSyntaxProto3";
578 break;
579 }
580 printer->Print(vars,
581 "#pragma mark - $root_class_name$_FileDescriptor\n"
582 "\n"
583 "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
584 " // This is called by +initialize so there is no need to worry\n"
585 " // about thread safety of the singleton.\n"
586 " static GPBFileDescriptor *descriptor = NULL;\n"
587 " if (!descriptor) {\n"
588 " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n");
589 if (!vars["objc_prefix"].empty()) {
590 printer->Print(
591 vars,
592 " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
593 " objcPrefix:@\"$objc_prefix$\"\n"
594 " syntax:$syntax$];\n");
595 } else {
596 printer->Print(
597 vars,
598 " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
599 " syntax:$syntax$];\n");
600 }
601 printer->Print(
602 " }\n"
603 " return descriptor;\n"
604 "}\n"
605 "\n");
606 }
607
608 for (const auto& generator : enum_generators_) {
609 generator->GenerateSource(printer);
610 }
611 for (const auto& generator : message_generators_) {
612 generator->GenerateSource(printer);
613 }
614
615 printer->Print(
616 "\n"
617 "#pragma clang diagnostic pop\n"
618 "\n"
619 "// @@protoc_insertion_point(global_scope)\n");
620 }
621
622 // Helper to print the import of the runtime support at the top of generated
623 // files. This currently only supports the runtime coming from a framework
624 // as defined by the official CocoaPod.
PrintFileRuntimePreamble(io::Printer * printer,const std::vector<std::string> & headers_to_import) const625 void FileGenerator::PrintFileRuntimePreamble(
626 io::Printer* printer,
627 const std::vector<std::string>& headers_to_import) const {
628 printer->Print(
629 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
630 "// source: $filename$\n"
631 "\n",
632 "filename", file_->name());
633
634 if (is_bundled_proto_) {
635 // This is basically a clone of ImportWriter::PrintRuntimeImports() but
636 // without the CPP symbol gate, since within the bundled files, that isn't
637 // needed.
638 std::string import_prefix = generation_options_.runtime_import_prefix;
639 if (!import_prefix.empty()) {
640 import_prefix += "/";
641 }
642 for (const auto& header : headers_to_import) {
643 printer->Print(
644 "#import \"$import_prefix$$header$\"\n",
645 "import_prefix", import_prefix,
646 "header", header);
647 }
648 } else {
649 ImportWriter::PrintRuntimeImports(
650 printer, headers_to_import, generation_options_.runtime_import_prefix, true);
651 }
652
653 printer->Print("\n");
654 }
655
656 } // namespace objectivec
657 } // namespace compiler
658 } // namespace protobuf
659 } // namespace google
660