objectivec_file.cc 23 KB

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