|
|
|
@ -43,7 +43,6 @@ |
|
|
|
|
#include "absl/container/btree_set.h" |
|
|
|
|
#include "absl/container/flat_hash_map.h" |
|
|
|
|
#include "absl/container/flat_hash_set.h" |
|
|
|
|
#include "absl/strings/str_cat.h" |
|
|
|
|
#include "absl/strings/str_join.h" |
|
|
|
|
#include "google/protobuf/compiler/objectivec/enum.h" |
|
|
|
|
#include "google/protobuf/compiler/objectivec/extension.h" |
|
|
|
@ -67,10 +66,6 @@ const int32_t GOOGLE_PROTOBUF_OBJC_VERSION = 30005; |
|
|
|
|
|
|
|
|
|
const char* kHeaderExtension = ".pbobjc.h"; |
|
|
|
|
|
|
|
|
|
std::string BundledFileName(const FileDescriptor* file) { |
|
|
|
|
return "GPB" + FilePathBasename(file) + kHeaderExtension; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Checks if a message contains any extension definitions (on the message or
|
|
|
|
|
// a nested message under it).
|
|
|
|
|
bool MessageContainsExtensions(const Descriptor* message) { |
|
|
|
@ -412,20 +407,17 @@ void FileGenerator::GenerateHeader(io::Printer* printer) const { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileGenerator::GenerateSource(io::Printer* printer) const { |
|
|
|
|
// #import the runtime support.
|
|
|
|
|
std::vector<std::string> headers; |
|
|
|
|
headers.push_back("GPBProtocolBuffers_RuntimeSupport.h"); |
|
|
|
|
if (is_bundled_proto_) { |
|
|
|
|
headers.push_back(BundledFileName(file_)); |
|
|
|
|
} |
|
|
|
|
PrintFileRuntimePreamble(printer, headers); |
|
|
|
|
ImportWriter import_writer( |
|
|
|
|
generation_options_.generate_for_named_framework, |
|
|
|
|
generation_options_.named_framework_to_proto_path_mappings_path, |
|
|
|
|
generation_options_.runtime_import_prefix, |
|
|
|
|
/* for_bundled_proto = */ is_bundled_proto_); |
|
|
|
|
const std::string header_extension(kHeaderExtension); |
|
|
|
|
|
|
|
|
|
// Enums use atomic in the generated code, so add the system import as needed.
|
|
|
|
|
if (!enum_generators_.empty()) { |
|
|
|
|
printer->Print( |
|
|
|
|
"#import <stdatomic.h>\n" |
|
|
|
|
"\n"); |
|
|
|
|
} |
|
|
|
|
// #import the runtime support.
|
|
|
|
|
import_writer.AddRuntimeImport("GPBProtocolBuffers_RuntimeSupport.h"); |
|
|
|
|
// #import the header for this proto file.
|
|
|
|
|
import_writer.AddFile(file_, header_extension); |
|
|
|
|
|
|
|
|
|
std::vector<const FileDescriptor*> deps_with_extensions = |
|
|
|
|
common_state_->CollectMinimalFileDepsContainingExtensions(file_); |
|
|
|
@ -435,52 +427,30 @@ void FileGenerator::GenerateSource(io::Printer* printer) const { |
|
|
|
|
generation_options_.headers_use_forward_declarations && |
|
|
|
|
!is_bundled_proto_; |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
ImportWriter import_writer( |
|
|
|
|
generation_options_.generate_for_named_framework, |
|
|
|
|
generation_options_.named_framework_to_proto_path_mappings_path, |
|
|
|
|
generation_options_.runtime_import_prefix, |
|
|
|
|
/* include_wkt_imports = */ false); |
|
|
|
|
const std::string header_extension(kHeaderExtension); |
|
|
|
|
|
|
|
|
|
// #import the header for this proto file.
|
|
|
|
|
import_writer.AddFile(file_, header_extension); |
|
|
|
|
|
|
|
|
|
if (headers_use_forward_declarations) { |
|
|
|
|
// #import the headers for anything that a plain dependency of this proto
|
|
|
|
|
// file (that means they were just an include, not a "public" include).
|
|
|
|
|
absl::flat_hash_set<std::string> public_import_names; |
|
|
|
|
for (int i = 0; i < file_->public_dependency_count(); i++) { |
|
|
|
|
public_import_names.insert(file_->public_dependency(i)->name()); |
|
|
|
|
} |
|
|
|
|
for (int i = 0; i < file_->dependency_count(); i++) { |
|
|
|
|
const FileDescriptor* dep = file_->dependency(i); |
|
|
|
|
if (!public_import_names.contains(dep->name())) { |
|
|
|
|
import_writer.AddFile(dep, header_extension); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (headers_use_forward_declarations) { |
|
|
|
|
// #import the headers for anything that a plain dependency of this proto
|
|
|
|
|
// file (that means they were just an include, not a "public" include).
|
|
|
|
|
absl::flat_hash_set<std::string> public_import_names; |
|
|
|
|
for (int i = 0; i < file_->public_dependency_count(); i++) { |
|
|
|
|
public_import_names.insert(file_->public_dependency(i)->name()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If any indirect dependency provided extensions, it needs to be directly
|
|
|
|
|
// imported so it can get merged into the root's extensions registry.
|
|
|
|
|
// See the Note by CollectMinimalFileDepsContainingExtensions before
|
|
|
|
|
// changing this.
|
|
|
|
|
for (std::vector<const FileDescriptor*>::iterator iter = |
|
|
|
|
deps_with_extensions.begin(); |
|
|
|
|
iter != deps_with_extensions.end(); ++iter) { |
|
|
|
|
if (!IsDirectDependency(*iter, file_)) { |
|
|
|
|
import_writer.AddFile(*iter, header_extension); |
|
|
|
|
for (int i = 0; i < file_->dependency_count(); i++) { |
|
|
|
|
const FileDescriptor* dep = file_->dependency(i); |
|
|
|
|
if (!public_import_names.contains(dep->name())) { |
|
|
|
|
import_writer.AddFile(dep, header_extension); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
import_writer.EmitFileImports(printer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool includes_oneof = false; |
|
|
|
|
for (const auto& generator : message_generators_) { |
|
|
|
|
if (generator->IncludesOneOfDefinition()) { |
|
|
|
|
includes_oneof = true; |
|
|
|
|
break; |
|
|
|
|
// If any indirect dependency provided extensions, it needs to be directly
|
|
|
|
|
// imported so it can get merged into the root's extensions registry.
|
|
|
|
|
// See the Note by CollectMinimalFileDepsContainingExtensions before
|
|
|
|
|
// changing this.
|
|
|
|
|
for (std::vector<const FileDescriptor*>::iterator iter = |
|
|
|
|
deps_with_extensions.begin(); |
|
|
|
|
iter != deps_with_extensions.end(); ++iter) { |
|
|
|
|
if (!IsDirectDependency(*iter, file_)) { |
|
|
|
|
import_writer.AddFile(*iter, header_extension); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -492,249 +462,261 @@ void FileGenerator::GenerateSource(io::Printer* printer) const { |
|
|
|
|
generator->DetermineObjectiveCClassDefinitions(&fwd_decls); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Note:
|
|
|
|
|
// deprecated-declarations suppression is only needed if some place in this
|
|
|
|
|
// proto file is something deprecated or if it references something from
|
|
|
|
|
// another file that is deprecated.
|
|
|
|
|
// dollar-in-identifier-extension is needed because we use references to
|
|
|
|
|
// objc class names that have $ in identifiers.
|
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"// @@protoc_insertion_point(imports)\n" |
|
|
|
|
"\n" |
|
|
|
|
"#pragma clang diagnostic push\n" |
|
|
|
|
"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
if (includes_oneof) { |
|
|
|
|
// The generated code for oneof's uses direct ivar access, suppress the
|
|
|
|
|
// warning in case developer turn that on in the context they compile the
|
|
|
|
|
// generated code.
|
|
|
|
|
printer->Print( |
|
|
|
|
"#pragma clang diagnostic ignored \"-Wdirect-ivar-access\"\n"); |
|
|
|
|
} |
|
|
|
|
if (!fwd_decls.empty()) { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"#pragma clang diagnostic ignored \"-Wdollar-in-identifier-extension\"\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} |
|
|
|
|
printer->Print("\n"); |
|
|
|
|
if (!fwd_decls.empty()) { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"#pragma mark - Objective C Class declarations\n" |
|
|
|
|
"// Forward declarations of Objective C classes that we can use as\n" |
|
|
|
|
"// static values in struct initializers.\n" |
|
|
|
|
"// We don't use [Foo class] because it is not a static value.\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} |
|
|
|
|
for (const auto& i : fwd_decls) { |
|
|
|
|
printer->Print("$value$\n", "value", i); |
|
|
|
|
} |
|
|
|
|
if (!fwd_decls.empty()) { |
|
|
|
|
printer->Print("\n"); |
|
|
|
|
} |
|
|
|
|
printer->Print( |
|
|
|
|
// clang-format off
|
|
|
|
|
"#pragma mark - $root_class_name$\n" |
|
|
|
|
"\n" |
|
|
|
|
"@implementation $root_class_name$\n\n", |
|
|
|
|
// clang-format on
|
|
|
|
|
"root_class_name", root_class_name_); |
|
|
|
|
|
|
|
|
|
const bool file_contains_extensions = !extension_generators_.empty(); |
|
|
|
|
|
|
|
|
|
// If there were any extensions or this file has any dependencies, output
|
|
|
|
|
// a registry to override to create the file specific registry.
|
|
|
|
|
if (file_contains_extensions || !deps_with_extensions.empty()) { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"+ (GPBExtensionRegistry*)extensionRegistry {\n" |
|
|
|
|
" // This is called by +initialize so there is no need to worry\n" |
|
|
|
|
" // about thread safety and initialization of registry.\n" |
|
|
|
|
" static GPBExtensionRegistry* registry = nil;\n" |
|
|
|
|
" if (!registry) {\n" |
|
|
|
|
" GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n" |
|
|
|
|
" registry = [[GPBExtensionRegistry alloc] init];\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
printer->Indent(); |
|
|
|
|
printer->Indent(); |
|
|
|
|
|
|
|
|
|
if (file_contains_extensions) { |
|
|
|
|
printer->Print("static GPBExtensionDescription descriptions[] = {\n"); |
|
|
|
|
printer->Indent(); |
|
|
|
|
for (const auto& generator : extension_generators_) { |
|
|
|
|
generator->GenerateStaticVariablesInitialization(printer); |
|
|
|
|
} |
|
|
|
|
printer->Outdent(); |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"};\n" |
|
|
|
|
"for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) {\n" |
|
|
|
|
" GPBExtensionDescriptor *extension =\n" |
|
|
|
|
" [[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i]\n" |
|
|
|
|
" usesClassRefs:YES];\n" |
|
|
|
|
" [registry addExtension:extension];\n" |
|
|
|
|
" [self globallyRegisterExtension:extension];\n" |
|
|
|
|
" [extension release];\n" |
|
|
|
|
"}\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} |
|
|
|
|
printer->Emit( |
|
|
|
|
{ |
|
|
|
|
// Avoid the directive within the string below being seen by the
|
|
|
|
|
// tool.
|
|
|
|
|
{"clangfmt", "clang-format"}, |
|
|
|
|
{"filename", file_->name()}, |
|
|
|
|
{"root_class_name", root_class_name_}, |
|
|
|
|
{"runtime_imports", |
|
|
|
|
[&] { |
|
|
|
|
import_writer.EmitRuntimeImports( |
|
|
|
|
printer, /* default_cpp_symbol = */ !is_bundled_proto_); |
|
|
|
|
}}, |
|
|
|
|
{"file_imports", [&] { import_writer.EmitFileImports(printer); }}, |
|
|
|
|
{"extra_imports", |
|
|
|
|
[&] { |
|
|
|
|
// Enums use atomic in the generated code, so add the system import
|
|
|
|
|
// as needed.
|
|
|
|
|
if (!enum_generators_.empty()) { |
|
|
|
|
printer->Emit("#import <stdatomic.h>\n\n"); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
{"extra_pragmas", |
|
|
|
|
[&] { |
|
|
|
|
// The generated code for oneof's uses direct ivar access, suppress
|
|
|
|
|
// the warning in case developer turn that on in the context they
|
|
|
|
|
// compile the generated code.
|
|
|
|
|
for (const auto& generator : message_generators_) { |
|
|
|
|
if (generator->IncludesOneOfDefinition()) { |
|
|
|
|
printer->Emit(R"objc( |
|
|
|
|
#pragma clang diagnostic ignored "-Wdirect-ivar-access" |
|
|
|
|
)objc"); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!fwd_decls.empty()) { |
|
|
|
|
printer->Emit(R"objc( |
|
|
|
|
#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" |
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
{"fwd_decls", |
|
|
|
|
[&] { |
|
|
|
|
if (!fwd_decls.empty()) { |
|
|
|
|
printer->Emit({{"decls", absl::StrJoin(fwd_decls, "\n")}}, |
|
|
|
|
R"objc( |
|
|
|
|
#pragma mark - Objective C Class declarations |
|
|
|
|
// Forward declarations of Objective C classes that we can use as
|
|
|
|
|
// static values in struct initializers.
|
|
|
|
|
// We don't use [Foo class] because it is not a static value.
|
|
|
|
|
$decls$ |
|
|
|
|
|
|
|
|
|
if (deps_with_extensions.empty()) { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"// None of the imports (direct or indirect) defined extensions, so no need to add\n" |
|
|
|
|
"// them to this registry.\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} else { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"// Merge in the imports (direct or indirect) that defined extensions.\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
for (std::vector<const FileDescriptor*>::iterator iter = |
|
|
|
|
deps_with_extensions.begin(); |
|
|
|
|
iter != deps_with_extensions.end(); ++iter) { |
|
|
|
|
const std::string root_class_name(FileClassName((*iter))); |
|
|
|
|
printer->Print( |
|
|
|
|
"[registry addExtensions:[$dependency$ extensionRegistry]];\n", |
|
|
|
|
"dependency", root_class_name); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
{"root_implementation", |
|
|
|
|
[&] { EmitRootImplementation(printer, deps_with_extensions); }}, |
|
|
|
|
{"file_descriptor_implementation", |
|
|
|
|
[&] { EmitFileDescriptorImplementation(printer); }}, |
|
|
|
|
{"enums_and_messages", |
|
|
|
|
[&] { |
|
|
|
|
for (const auto& generator : enum_generators_) { |
|
|
|
|
generator->GenerateSource(printer); |
|
|
|
|
} |
|
|
|
|
for (const auto& generator : message_generators_) { |
|
|
|
|
generator->GenerateSource(printer); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
}, |
|
|
|
|
R"objc( |
|
|
|
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
|
|
|
// $clangfmt$ off
|
|
|
|
|
// source: $filename$
|
|
|
|
|
|
|
|
|
|
printer->Outdent(); |
|
|
|
|
printer->Outdent(); |
|
|
|
|
$runtime_imports$ |
|
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
" }\n" |
|
|
|
|
" return registry;\n" |
|
|
|
|
"}\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} else { |
|
|
|
|
if (file_->dependency_count() > 0) { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"// No extensions in the file and none of the imports (direct or indirect)\n" |
|
|
|
|
"// defined extensions, so no need to generate +extensionRegistry.\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} else { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"// No extensions in the file and no imports, so no need to generate\n" |
|
|
|
|
"// +extensionRegistry.\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
$extra_imports$; |
|
|
|
|
$file_imports$ |
|
|
|
|
// @@protoc_insertion_point(imports)
|
|
|
|
|
|
|
|
|
|
printer->Print("\n@end\n\n"); |
|
|
|
|
#pragma clang diagnostic push |
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations" |
|
|
|
|
$extra_pragmas$ |
|
|
|
|
|
|
|
|
|
// File descriptor only needed if there are messages to use it.
|
|
|
|
|
if (!message_generators_.empty()) { |
|
|
|
|
absl::flat_hash_map<absl::string_view, std::string> vars; |
|
|
|
|
vars["root_class_name"] = root_class_name_; |
|
|
|
|
vars["package"] = file_->package(); |
|
|
|
|
vars["objc_prefix"] = FileClassPrefix(file_); |
|
|
|
|
switch (file_->syntax()) { |
|
|
|
|
case FileDescriptor::SYNTAX_UNKNOWN: |
|
|
|
|
vars["syntax"] = "GPBFileSyntaxUnknown"; |
|
|
|
|
break; |
|
|
|
|
case FileDescriptor::SYNTAX_PROTO2: |
|
|
|
|
vars["syntax"] = "GPBFileSyntaxProto2"; |
|
|
|
|
break; |
|
|
|
|
case FileDescriptor::SYNTAX_PROTO3: |
|
|
|
|
vars["syntax"] = "GPBFileSyntaxProto3"; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
vars, |
|
|
|
|
"#pragma mark - $root_class_name$_FileDescriptor\n" |
|
|
|
|
"\n" |
|
|
|
|
"static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) {\n" |
|
|
|
|
" // This is called by +initialize so there is no need to worry\n" |
|
|
|
|
" // about thread safety of the singleton.\n" |
|
|
|
|
" static GPBFileDescriptor *descriptor = NULL;\n" |
|
|
|
|
" if (!descriptor) {\n" |
|
|
|
|
" GPB_DEBUG_CHECK_RUNTIME_VERSIONS();\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
if (!vars["objc_prefix"].empty()) { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
vars, |
|
|
|
|
" descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" |
|
|
|
|
" objcPrefix:@\"$objc_prefix$\"\n" |
|
|
|
|
" syntax:$syntax$];\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} else { |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
vars, |
|
|
|
|
" descriptor = [[GPBFileDescriptor alloc] initWithPackage:@\"$package$\"\n" |
|
|
|
|
" syntax:$syntax$];\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} |
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
" }\n" |
|
|
|
|
" return descriptor;\n" |
|
|
|
|
"}\n" |
|
|
|
|
"\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
} |
|
|
|
|
$fwd_decls$; |
|
|
|
|
$root_implementation$ |
|
|
|
|
|
|
|
|
|
for (const auto& generator : enum_generators_) { |
|
|
|
|
generator->GenerateSource(printer); |
|
|
|
|
} |
|
|
|
|
for (const auto& generator : message_generators_) { |
|
|
|
|
generator->GenerateSource(printer); |
|
|
|
|
} |
|
|
|
|
$file_descriptor_implementation$; |
|
|
|
|
$enums_and_messages$; |
|
|
|
|
|
|
|
|
|
#pragma clang diagnostic pop |
|
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"\n" |
|
|
|
|
"#pragma clang diagnostic pop\n" |
|
|
|
|
"\n" |
|
|
|
|
"// @@protoc_insertion_point(global_scope)\n" |
|
|
|
|
"\n" |
|
|
|
|
"// clang-format on\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
// @@protoc_insertion_point(global_scope)
|
|
|
|
|
|
|
|
|
|
// $clangfmt$ on
|
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Helper to print the import of the runtime support at the top of generated
|
|
|
|
|
// files. This currently only supports the runtime coming from a framework
|
|
|
|
|
// as defined by the official CocoaPod.
|
|
|
|
|
void FileGenerator::PrintFileRuntimePreamble( |
|
|
|
|
io::Printer* printer, |
|
|
|
|
const std::vector<std::string>& headers_to_import) const { |
|
|
|
|
printer->Print( |
|
|
|
|
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
|
|
|
|
"// clang-format off\n" |
|
|
|
|
"// source: $filename$\n" |
|
|
|
|
"\n", |
|
|
|
|
"filename", file_->name()); |
|
|
|
|
void FileGenerator::EmitRootImplementation( |
|
|
|
|
io::Printer* p, |
|
|
|
|
const std::vector<const FileDescriptor*>& deps_with_extensions) const { |
|
|
|
|
p->Emit( |
|
|
|
|
{ |
|
|
|
|
{"root_class_name", root_class_name_}, |
|
|
|
|
{"root_extension_registry", |
|
|
|
|
[&] { |
|
|
|
|
// If there were any extensions or this file has any dependencies,
|
|
|
|
|
// output a registry to override to create the file specific
|
|
|
|
|
// registry.
|
|
|
|
|
if (!!extension_generators_.empty() && |
|
|
|
|
deps_with_extensions.empty()) { |
|
|
|
|
if (file_->dependency_count() == 0) { |
|
|
|
|
p->Emit(R"objc( |
|
|
|
|
// No extensions in the file and no imports, so no need to generate
|
|
|
|
|
// +extensionRegistry.
|
|
|
|
|
)objc"); |
|
|
|
|
} else { |
|
|
|
|
p->Emit(R"objc( |
|
|
|
|
// No extensions in the file and none of the imports (direct or indirect)
|
|
|
|
|
// defined extensions, so no need to generate +extensionRegistry.
|
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
EmitRootExtensionRegistryImplementation(p, deps_with_extensions); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
}, |
|
|
|
|
R"objc( |
|
|
|
|
#pragma mark - $root_class_name$ |
|
|
|
|
|
|
|
|
|
@implementation $root_class_name$ |
|
|
|
|
|
|
|
|
|
if (is_bundled_proto_) { |
|
|
|
|
// This is basically a clone of ImportWriter::PrintRuntimeImports() but
|
|
|
|
|
// without the CPP symbol gate, since within the bundled files, that isn't
|
|
|
|
|
// needed.
|
|
|
|
|
std::string import_prefix = generation_options_.runtime_import_prefix; |
|
|
|
|
if (!import_prefix.empty()) { |
|
|
|
|
import_prefix += "/"; |
|
|
|
|
} |
|
|
|
|
for (const auto& header : headers_to_import) { |
|
|
|
|
printer->Print("#import \"$import_prefix$$header$\"\n", "import_prefix", |
|
|
|
|
import_prefix, "header", header); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
ImportWriter::EmitRuntimeImports(printer, headers_to_import, |
|
|
|
|
generation_options_.runtime_import_prefix, |
|
|
|
|
/* is_bundled_proto = */ false, |
|
|
|
|
/* default_cpp_symbol = */ true); |
|
|
|
|
$root_extension_registry$ |
|
|
|
|
|
|
|
|
|
@end |
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileGenerator::EmitRootExtensionRegistryImplementation( |
|
|
|
|
io::Printer* p, |
|
|
|
|
const std::vector<const FileDescriptor*>& deps_with_extensions) const { |
|
|
|
|
p->Emit( |
|
|
|
|
{ |
|
|
|
|
{"register_local_extensions", |
|
|
|
|
[&] { |
|
|
|
|
if (extension_generators_.empty()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
p->Emit(R"objc( |
|
|
|
|
static GPBExtensionDescription descriptions[] = { |
|
|
|
|
$register_local_extensions_variable_blocks$ |
|
|
|
|
}; |
|
|
|
|
for (size_t i = 0; i < sizeof(descriptions) / sizeof(descriptions[0]); ++i) { |
|
|
|
|
GPBExtensionDescriptor *extension = |
|
|
|
|
[[GPBExtensionDescriptor alloc] initWithExtensionDescription:&descriptions[i] |
|
|
|
|
usesClassRefs:YES]; |
|
|
|
|
[registry addExtension:extension]; |
|
|
|
|
[self globallyRegisterExtension:extension]; |
|
|
|
|
[extension release]; |
|
|
|
|
} |
|
|
|
|
)objc"); |
|
|
|
|
}}, |
|
|
|
|
{"register_local_extensions_variable_blocks", |
|
|
|
|
[&] { |
|
|
|
|
for (const auto& generator : extension_generators_) { |
|
|
|
|
generator->GenerateStaticVariablesInitialization(p); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
{"register_imports", |
|
|
|
|
[&] { |
|
|
|
|
if (deps_with_extensions.empty()) { |
|
|
|
|
p->Emit(R"objc( |
|
|
|
|
// None of the imports (direct or indirect) defined extensions, so no need to add
|
|
|
|
|
// them to this registry.
|
|
|
|
|
)objc"); |
|
|
|
|
} else { |
|
|
|
|
p->Emit(R"objc( |
|
|
|
|
// Merge in the imports (direct or indirect) that defined extensions.
|
|
|
|
|
)objc"); |
|
|
|
|
for (const auto& dep : deps_with_extensions) { |
|
|
|
|
p->Emit({{"dependency", FileClassName(dep)}}, |
|
|
|
|
R"objc( |
|
|
|
|
[registry addExtensions:[$dependency$ extensionRegistry]]; |
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
}, |
|
|
|
|
R"objc( |
|
|
|
|
+ (GPBExtensionRegistry*)extensionRegistry { |
|
|
|
|
// This is called by +initialize so there is no need to worry
|
|
|
|
|
// about thread safety and initialization of registry.
|
|
|
|
|
static GPBExtensionRegistry* registry = nil; |
|
|
|
|
if (!registry) { |
|
|
|
|
GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); |
|
|
|
|
registry = [[GPBExtensionRegistry alloc] init]; |
|
|
|
|
$register_local_extensions$; |
|
|
|
|
$register_imports$ |
|
|
|
|
} |
|
|
|
|
return registry; |
|
|
|
|
} |
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileGenerator::EmitFileDescriptorImplementation(io::Printer* p) const { |
|
|
|
|
// File descriptor only needed if there are messages to use it.
|
|
|
|
|
if (message_generators_.empty()) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printer->Print("\n"); |
|
|
|
|
std::string syntax; |
|
|
|
|
switch (file_->syntax()) { |
|
|
|
|
case FileDescriptor::SYNTAX_UNKNOWN: |
|
|
|
|
syntax = "GPBFileSyntaxUnknown"; |
|
|
|
|
break; |
|
|
|
|
case FileDescriptor::SYNTAX_PROTO2: |
|
|
|
|
syntax = "GPBFileSyntaxProto2"; |
|
|
|
|
break; |
|
|
|
|
case FileDescriptor::SYNTAX_PROTO3: |
|
|
|
|
syntax = "GPBFileSyntaxProto3"; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
const std::string objc_prefix(FileClassPrefix(file_)); |
|
|
|
|
|
|
|
|
|
p->Emit( |
|
|
|
|
{ |
|
|
|
|
{"root_class_name", root_class_name_}, |
|
|
|
|
{"package", file_->package()}, |
|
|
|
|
{"objc_prefix", objc_prefix}, |
|
|
|
|
{"objc_prefix_arg", |
|
|
|
|
[&] { |
|
|
|
|
if (!objc_prefix.empty()) { |
|
|
|
|
p->Emit(R"objc( |
|
|
|
|
objcPrefix:@"$objc_prefix$" |
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
{"syntax", syntax}, |
|
|
|
|
}, |
|
|
|
|
R"objc( |
|
|
|
|
#pragma mark - $root_class_name$_FileDescriptor |
|
|
|
|
|
|
|
|
|
static GPBFileDescriptor *$root_class_name$_FileDescriptor(void) { |
|
|
|
|
// This is called by +initialize so there is no need to worry
|
|
|
|
|
// about thread safety of the singleton.
|
|
|
|
|
static GPBFileDescriptor *descriptor = NULL; |
|
|
|
|
if (!descriptor) { |
|
|
|
|
GPB_DEBUG_CHECK_RUNTIME_VERSIONS(); |
|
|
|
|
descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"$package$" |
|
|
|
|
$objc_prefix_arg$; |
|
|
|
|
syntax:$syntax$]; |
|
|
|
|
} |
|
|
|
|
return descriptor; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // namespace objectivec
|
|
|
|
|