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_message.h>
35 #include <google/protobuf/compiler/code_generator.h>
36 #include <google/protobuf/io/printer.h>
37 #include <google/protobuf/io/zero_copy_stream_impl.h>
38 #include <google/protobuf/stubs/stl_util.h>
39 #include <google/protobuf/stubs/strutil.h>
50 namespace objectivec {
57 const char* kHeaderExtension =
".pbobjc.h";
62 if (
message->enum_type_count() > 0) {
65 for (
int i = 0;
i <
message->nested_type_count();
i++) {
66 if (MessageContainsEnums(
message->nested_type(i))) {
76 if (
message->extension_count() > 0) {
79 for (
int i = 0;
i <
message->nested_type_count();
i++) {
80 if (MessageContainsExtensions(
message->nested_type(i))) {
90 if (
file->enum_type_count() > 0) {
93 for (
int i = 0;
i <
file->message_type_count();
i++) {
94 if (MessageContainsEnums(
file->message_type(i))) {
104 if (
file->extension_count() > 0) {
107 for (
int i = 0;
i <
file->message_type_count();
i++) {
108 if (MessageContainsExtensions(
file->message_type(i))) {
117 void PruneFileAndDepsMarkingAsVisited(
119 std::vector<const FileDescriptor*>*
files,
120 std::set<const FileDescriptor*>* files_visited) {
126 files_visited->insert(
file);
127 for (
int i = 0;
i <
file->dependency_count();
i++) {
128 PruneFileAndDepsMarkingAsVisited(
file->dependency(i),
files, files_visited);
133 void CollectMinimalFileDepsContainingExtensionsWorker(
135 std::vector<const FileDescriptor*>*
files,
136 std::set<const FileDescriptor*>* files_visited) {
137 if (files_visited->find(
file) != files_visited->end()) {
140 files_visited->insert(
file);
142 if (FileContainsExtensions(
file)) {
144 for (
int i = 0;
i <
file->dependency_count();
i++) {
146 PruneFileAndDepsMarkingAsVisited(
dep,
files, files_visited);
149 for (
int i = 0;
i <
file->dependency_count();
i++) {
151 CollectMinimalFileDepsContainingExtensionsWorker(
dep,
files,
166 void CollectMinimalFileDepsContainingExtensions(
168 std::vector<const FileDescriptor*>*
files) {
169 std::set<const FileDescriptor*> files_visited;
170 for (
int i = 0;
i <
file->dependency_count();
i++) {
172 CollectMinimalFileDepsContainingExtensionsWorker(
dep,
files,
178 for (
int i = 0;
i <
file->dependency_count();
i++) {
179 if (
dep ==
file->dependency(i)) {
194 EnumGenerator* generator =
new EnumGenerator(
file_->
enum_type(i));
198 MessageGenerator* generator =
203 ExtensionGenerator* generator =
212 std::vector<std::string> headers;
216 headers.push_back(
"GPBDescriptor.h");
217 headers.push_back(
"GPBMessage.h");
218 headers.push_back(
"GPBRootObject.h");
220 headers.push_back(
"GPBProtocolBuffers.h");
231 "#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n"
232 "#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n"
234 "#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n"
235 "#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n"
242 ImportWriter import_writer(
247 const std::string header_extension(kHeaderExtension);
251 import_writer.Print(printer);
259 "// @@protoc_insertion_point(imports)\n"
261 "#pragma clang diagnostic push\n"
262 "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"
264 "CF_EXTERN_C_BEGIN\n"
267 std::set<std::string> fwd_decls;
269 generator->DetermineForwardDeclarations(&fwd_decls);
271 for (std::set<std::string>::const_iterator
i(fwd_decls.begin());
272 i != fwd_decls.end(); ++i) {
273 printer->Print(
"$value$;\n",
"value", *i);
275 if (fwd_decls.begin() != fwd_decls.end()) {
276 printer->Print(
"\n");
280 "NS_ASSUME_NONNULL_BEGIN\n"
285 generator->GenerateHeader(printer);
289 generator->GenerateEnumHeader(printer);
295 "#pragma mark - $root_class_name$\n"
298 " * Exposes the extension registry for this file.\n"
300 " * The base class provides:\n"
302 " * + (GPBExtensionRegistry *)extensionRegistry;\n"
304 " * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n"
305 " * this file and all files that it depends on.\n"
307 "GPB_FINAL @interface $root_class_name$ : GPBRootObject\n"
315 "@interface $root_class_name$ (DynamicMethods)\n",
319 generator->GenerateMembersHeader(printer);
322 printer->Print(
"@end\n\n");
326 generator->GenerateMessageHeader(printer);
330 "NS_ASSUME_NONNULL_END\n"
334 "#pragma clang diagnostic pop\n"
336 "// @@protoc_insertion_point(global_scope)\n");
341 std::vector<std::string> headers;
342 headers.push_back(
"GPBProtocolBuffers_RuntimeSupport.h");
346 if (FileContainsEnums(
file_)) {
348 "#import <stdatomic.h>\n"
352 std::vector<const FileDescriptor*> deps_with_extensions;
353 CollectMinimalFileDepsContainingExtensions(
file_, &deps_with_extensions);
356 ImportWriter import_writer(
361 const std::string header_extension(kHeaderExtension);
364 import_writer.AddFile(
file_, header_extension);
368 std::set<std::string> public_import_names;
374 bool public_import = (public_import_names.count(
dep->name()) != 0);
375 if (!public_import) {
376 import_writer.AddFile(
dep, header_extension);
385 deps_with_extensions.begin();
386 iter != deps_with_extensions.end(); ++
iter) {
388 import_writer.AddFile(*
iter, header_extension);
392 import_writer.Print(printer);
395 bool includes_oneof =
false;
397 if (generator->IncludesOneOfDefinition()) {
398 includes_oneof =
true;
403 std::set<std::string> fwd_decls;
405 generator->DetermineObjectiveCClassDefinitions(&fwd_decls);
408 generator->DetermineObjectiveCClassDefinitions(&fwd_decls);
418 "// @@protoc_insertion_point(imports)\n"
420 "#pragma clang diagnostic push\n"
421 "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n");
422 if (includes_oneof) {
427 "#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n");
429 if (!fwd_decls.empty()) {
431 "#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n");
435 if (!fwd_decls.empty()) {
437 "#pragma mark - Objective C Class declarations\n"
438 "// Forward declarations of Objective C classes that we can use as\n"
439 "// static values in struct initializers.\n"
440 "// We don't use [Foo class] because it is not a static value.\n");
442 for (
const auto& i : fwd_decls) {
443 printer->Print(
"$value$\n",
"value", i);
445 if (!fwd_decls.empty()) {
446 printer->Print(
"\n");
449 "#pragma mark - $root_class_name$\n"
451 "@implementation $root_class_name$\n\n",
454 const bool file_contains_extensions = FileContainsExtensions(
file_);
458 if (file_contains_extensions || !deps_with_extensions.empty()) {
460 "+ (GPBExtensionRegistry*)extensionRegistry {\n"
461 " // This is called by +initialize so there is no need to worry\n"
462 " // about thread safety and initialization of registry.\n"
463 " static GPBExtensionRegistry* registry = nil;\n"
464 " if (!registry) {\n"
465 " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"
466 " registry = [[GPBExtensionRegistry alloc] init];\n");
471 if (file_contains_extensions) {
473 "static GPBExtensionDescription descriptions[] = {\n");
476 generator->GenerateStaticVariablesInitialization(printer);
479 generator->GenerateStaticVariablesInitialization(printer);
484 "for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n"
485 " GPBExtensionDescriptor *extension =\n"
486 " [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]\n"
487 " usesClassRefs:YES];\n"
488 " [registry addExtension:extension];\n"
489 " [self globallyRegisterExtension:extension];\n"
490 " [extension release];\n"
494 if (deps_with_extensions.empty()) {
496 "// None of the imports (direct or indirect) defined extensions, so no need to add\n"
497 "// them to this registry.\n");
500 "// Merge in the imports (direct or indirect) that defined extensions.\n");
502 deps_with_extensions.begin();
503 iter != deps_with_extensions.end(); ++
iter) {
506 "[registry addExtensions:[$dependency$ extensionRegistry]];\n",
507 "dependency", root_class_name);
516 " return registry;\n"
521 "// No extensions in the file and none of the imports (direct or indirect)\n"
522 "// defined extensions, so no need to generate +extensionRegistry.\n");
525 "// No extensions in the file and no imports, so no need to generate\n"
526 "// +extensionRegistry.\n");
530 printer->Print(
"\n@end\n\n");
534 std::map<std::string, std::string> vars;
540 vars[
"syntax"] =
"GPBFileSyntaxUnknown";
543 vars[
"syntax"] =
"GPBFileSyntaxProto2";
546 vars[
"syntax"] =
"GPBFileSyntaxProto3";
550 "#pragma mark - $root_class_name$_FileDescriptor\n"
552 "static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n"
553 " // This is called by +initialize so there is no need to worry\n"
554 " // about thread safety of the singleton.\n"
555 " static GPBFileDescriptor *descriptor = NULL;\n"
556 " if (!descriptor) {\n"
557 " GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n");
558 if (!vars[
"objc_prefix"].
empty()) {
561 " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
562 " objcPrefix:@\"$objc_prefix$\"\n"
563 " syntax:$syntax$];\n");
567 " descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n"
568 " syntax:$syntax$];\n");
572 " return descriptor;\n"
578 generator->GenerateSource(printer);
581 generator->GenerateSource(printer);
586 "#pragma clang diagnostic pop\n"
588 "// @@protoc_insertion_point(global_scope)\n");
596 const std::vector<std::string>& headers_to_import)
const {
598 "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"
599 "// source: $filename$\n"
604 printer->Print(
"\n");