|
|
|
@ -44,6 +44,7 @@ |
|
|
|
|
#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" |
|
|
|
|
#include "google/protobuf/compiler/objectivec/import_writer.h" |
|
|
|
@ -242,155 +243,172 @@ FileGenerator::FileGenerator(const FileDescriptor* file, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileGenerator::GenerateHeader(io::Printer* printer) const { |
|
|
|
|
std::vector<std::string> headers; |
|
|
|
|
// Generated files bundled with the library get minimal imports, everything
|
|
|
|
|
// else gets the wrapper so everything is usable.
|
|
|
|
|
if (is_bundled_proto_) { |
|
|
|
|
headers.push_back("GPBDescriptor.h"); |
|
|
|
|
headers.push_back("GPBMessage.h"); |
|
|
|
|
headers.push_back("GPBRootObject.h"); |
|
|
|
|
for (int i = 0; i < file_->dependency_count(); i++) { |
|
|
|
|
const std::string header_name = BundledFileName(file_->dependency(i)); |
|
|
|
|
headers.push_back(header_name); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
headers.push_back("GPBProtocolBuffers.h"); |
|
|
|
|
} |
|
|
|
|
PrintFileRuntimePreamble(printer, headers); |
|
|
|
|
|
|
|
|
|
// Add some verification that the generated code matches the source the
|
|
|
|
|
// code is being compiled with.
|
|
|
|
|
// NOTE: This captures the raw numeric values at the time the generator was
|
|
|
|
|
// compiled, since that will be the versions for the ObjC runtime at that
|
|
|
|
|
// time. The constants in the generated code will then get their values at
|
|
|
|
|
// at compile time (so checking against the headers being used to compile).
|
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$\n" |
|
|
|
|
"#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources.\n" |
|
|
|
|
"#endif\n" |
|
|
|
|
"#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION\n" |
|
|
|
|
"#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources.\n" |
|
|
|
|
"#endif\n" |
|
|
|
|
"\n", |
|
|
|
|
"google_protobuf_objc_version", absl::StrCat(GOOGLE_PROTOBUF_OBJC_VERSION)); |
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
// The bundled protos (WKTs) don't use of forward declarations.
|
|
|
|
|
bool headers_use_forward_declarations = |
|
|
|
|
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); |
|
|
|
|
if (headers_use_forward_declarations) { |
|
|
|
|
// #import any headers for "public imports" in the proto file.
|
|
|
|
|
for (int i = 0; i < file_->public_dependency_count(); i++) { |
|
|
|
|
import_writer.AddFile(file_->public_dependency(i), header_extension); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
for (int i = 0; i < file_->dependency_count(); i++) { |
|
|
|
|
import_writer.AddFile(file_->dependency(i), header_extension); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
import_writer.Emit(printer); |
|
|
|
|
} |
|
|
|
|
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); |
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"// @@protoc_insertion_point(imports)\n" |
|
|
|
|
"\n" |
|
|
|
|
"#pragma clang diagnostic push\n" |
|
|
|
|
"#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" |
|
|
|
|
"\n" |
|
|
|
|
"CF_EXTERN_C_BEGIN\n" |
|
|
|
|
"\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
|
|
absl::btree_set<std::string> fwd_decls; |
|
|
|
|
for (const auto& generator : message_generators_) { |
|
|
|
|
generator->DetermineForwardDeclarations( |
|
|
|
|
&fwd_decls, |
|
|
|
|
/* include_external_types = */ headers_use_forward_declarations); |
|
|
|
|
} |
|
|
|
|
for (const auto& fwd_decl : fwd_decls) { |
|
|
|
|
printer->Print("$value$;\n", "value", fwd_decl); |
|
|
|
|
} |
|
|
|
|
if (fwd_decls.begin() != fwd_decls.end()) { |
|
|
|
|
printer->Print("\n"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printer->Print( |
|
|
|
|
"NS_ASSUME_NONNULL_BEGIN\n" |
|
|
|
|
"\n"); |
|
|
|
|
|
|
|
|
|
// need to write out all enums first
|
|
|
|
|
for (const auto& generator : enum_generators_) { |
|
|
|
|
generator->GenerateHeader(printer); |
|
|
|
|
// Generated files bundled with the library get minimal imports, everything
|
|
|
|
|
// else gets the wrapper so everything is usable.
|
|
|
|
|
if (is_bundled_proto_) { |
|
|
|
|
import_writer.AddRuntimeImport("GPBDescriptor.h"); |
|
|
|
|
import_writer.AddRuntimeImport("GPBMessage.h"); |
|
|
|
|
import_writer.AddRuntimeImport("GPBRootObject.h"); |
|
|
|
|
} else { |
|
|
|
|
import_writer.AddRuntimeImport("GPBProtocolBuffers.h"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// For extensions to chain together, the Root gets created even if there
|
|
|
|
|
// are no extensions.
|
|
|
|
|
printer->Print( |
|
|
|
|
// clang-format off
|
|
|
|
|
"#pragma mark - $root_class_name$\n" |
|
|
|
|
"\n" |
|
|
|
|
"/**\n" |
|
|
|
|
" * Exposes the extension registry for this file.\n" |
|
|
|
|
" *\n" |
|
|
|
|
" * The base class provides:\n" |
|
|
|
|
" * @code\n" |
|
|
|
|
" * + (GPBExtensionRegistry *)extensionRegistry;\n" |
|
|
|
|
" * @endcode\n" |
|
|
|
|
" * which is a @c GPBExtensionRegistry that includes all the extensions defined by\n" |
|
|
|
|
" * this file and all files that it depends on.\n" |
|
|
|
|
" **/\n" |
|
|
|
|
"GPB_FINAL @interface $root_class_name$ : GPBRootObject\n" |
|
|
|
|
"@end\n" |
|
|
|
|
"\n", |
|
|
|
|
// clang-format off
|
|
|
|
|
"root_class_name", root_class_name_); |
|
|
|
|
|
|
|
|
|
// The dynamic methods block is only needed if there are extensions that are
|
|
|
|
|
// file level scoped (not message scoped). The first file_->extension_count()
|
|
|
|
|
// of extension_generators_ are the file scoped ones.
|
|
|
|
|
if (file_->extension_count()) { |
|
|
|
|
printer->Print( |
|
|
|
|
"@interface $root_class_name$ (DynamicMethods)\n", |
|
|
|
|
"root_class_name", root_class_name_); |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < file_->extension_count(); i++) { |
|
|
|
|
extension_generators_[i]->GenerateMembersHeader(printer); |
|
|
|
|
if (headers_use_forward_declarations) { |
|
|
|
|
// #import any headers for "public imports" in the proto file.
|
|
|
|
|
for (int i = 0; i < file_->public_dependency_count(); i++) { |
|
|
|
|
import_writer.AddFile(file_->public_dependency(i), header_extension); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
for (int i = 0; i < file_->dependency_count(); i++) { |
|
|
|
|
import_writer.AddFile(file_->dependency(i), header_extension); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printer->Print("@end\n\n"); |
|
|
|
|
} // file_->extension_count()
|
|
|
|
|
|
|
|
|
|
for (const auto& generator : message_generators_) { |
|
|
|
|
generator->GenerateMessageHeader(printer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
|
printer->Print( |
|
|
|
|
"NS_ASSUME_NONNULL_END\n" |
|
|
|
|
"\n" |
|
|
|
|
"CF_EXTERN_C_END\n" |
|
|
|
|
"\n" |
|
|
|
|
"#pragma clang diagnostic pop\n" |
|
|
|
|
"\n" |
|
|
|
|
"// @@protoc_insertion_point(global_scope)\n" |
|
|
|
|
"\n" |
|
|
|
|
"// clange-format on\n"); |
|
|
|
|
// clang-format on
|
|
|
|
|
printer->Emit( |
|
|
|
|
{ |
|
|
|
|
// Avoid the directive within the string below being seen by the
|
|
|
|
|
// tool.
|
|
|
|
|
{"clangfmt", "clang-format"}, |
|
|
|
|
{"filename", file_->name()}, |
|
|
|
|
// For extensions to chain together, the Root gets created even if
|
|
|
|
|
// there are no extensions.
|
|
|
|
|
{"root_class_name", root_class_name_}, |
|
|
|
|
{"runtime_imports", |
|
|
|
|
[&] { |
|
|
|
|
import_writer.EmitRuntimeImports( |
|
|
|
|
printer, /* default_cpp_symbol = */ !is_bundled_proto_); |
|
|
|
|
}}, |
|
|
|
|
// Add some verification that the generated code matches the source
|
|
|
|
|
// the code is being compiled with.
|
|
|
|
|
//
|
|
|
|
|
// NOTE: Where used, this captures the raw numeric values at the
|
|
|
|
|
// time the generator was compiled, since that will be the versions
|
|
|
|
|
// for the ObjC runtime at that time. The constants in the
|
|
|
|
|
// generated code will then get their values at at compile time (so
|
|
|
|
|
// checking against the headers being used to compile).
|
|
|
|
|
{"google_protobuf_objc_version", GOOGLE_PROTOBUF_OBJC_VERSION}, |
|
|
|
|
{"file_imports", [&] { import_writer.EmitFileImports(printer); }}, |
|
|
|
|
{"fwd_decls", |
|
|
|
|
[&] { |
|
|
|
|
absl::btree_set<std::string> fwd_decls; |
|
|
|
|
for (const auto& generator : message_generators_) { |
|
|
|
|
generator->DetermineForwardDeclarations( |
|
|
|
|
&fwd_decls, |
|
|
|
|
/* include_external_types = */ |
|
|
|
|
headers_use_forward_declarations); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!fwd_decls.empty()) { |
|
|
|
|
printer->Emit({{"decls", absl::StrJoin(fwd_decls, "\n")}}, |
|
|
|
|
R"objc( |
|
|
|
|
$decls$ |
|
|
|
|
|
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
{"enums", |
|
|
|
|
[&] { |
|
|
|
|
for (const auto& generator : enum_generators_) { |
|
|
|
|
generator->GenerateHeader(printer); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
{"root_extensions", |
|
|
|
|
[&] { |
|
|
|
|
// The dynamic methods block is only needed if there are
|
|
|
|
|
// extensions that are file level scoped (not message scoped).
|
|
|
|
|
// The first file_->extension_count() of extension_generators_
|
|
|
|
|
// are the file scoped ones.
|
|
|
|
|
if (file_->extension_count()) { |
|
|
|
|
printer->Emit( |
|
|
|
|
{ |
|
|
|
|
{"extension_methods", |
|
|
|
|
[&] { |
|
|
|
|
for (int i = 0; i < file_->extension_count(); i++) { |
|
|
|
|
extension_generators_[i]->GenerateMembersHeader( |
|
|
|
|
printer); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
}, |
|
|
|
|
R"objc( |
|
|
|
|
@interface $root_class_name$ (DynamicMethods) |
|
|
|
|
$extension_methods$; |
|
|
|
|
@end |
|
|
|
|
|
|
|
|
|
)objc"); |
|
|
|
|
} // file_->extension_count()
|
|
|
|
|
}}, |
|
|
|
|
{"messages", |
|
|
|
|
[&] { |
|
|
|
|
for (const auto& generator : message_generators_) { |
|
|
|
|
generator->GenerateMessageHeader(printer); |
|
|
|
|
} |
|
|
|
|
}}, |
|
|
|
|
}, |
|
|
|
|
R"objc( |
|
|
|
|
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
|
|
|
// $clangfmt$ off
|
|
|
|
|
// source: $filename$
|
|
|
|
|
|
|
|
|
|
$runtime_imports$ |
|
|
|
|
|
|
|
|
|
#if GOOGLE_PROTOBUF_OBJC_VERSION < $google_protobuf_objc_version$ |
|
|
|
|
#error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. |
|
|
|
|
#endif |
|
|
|
|
#if $google_protobuf_objc_version$ < GOOGLE_PROTOBUF_OBJC_MIN_SUPPORTED_VERSION |
|
|
|
|
#error This file was generated by an older version of protoc which is incompatible with your Protocol Buffer library sources. |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
$file_imports$ |
|
|
|
|
// @@protoc_insertion_point(imports)
|
|
|
|
|
|
|
|
|
|
#pragma clang diagnostic push |
|
|
|
|
#pragma clang diagnostic ignored "-Wdeprecated-declarations" |
|
|
|
|
|
|
|
|
|
CF_EXTERN_C_BEGIN |
|
|
|
|
|
|
|
|
|
$fwd_decls$; |
|
|
|
|
NS_ASSUME_NONNULL_BEGIN |
|
|
|
|
|
|
|
|
|
$enums$; |
|
|
|
|
#pragma mark - $root_class_name$ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Exposes the extension registry for this file. |
|
|
|
|
* |
|
|
|
|
* The base class provides: |
|
|
|
|
* @code |
|
|
|
|
* + (GPBExtensionRegistry *)extensionRegistry; |
|
|
|
|
* @endcode |
|
|
|
|
* which is a @c GPBExtensionRegistry that includes all the extensions defined by |
|
|
|
|
* this file and all files that it depends on. |
|
|
|
|
**/ |
|
|
|
|
GPB_FINAL @interface $root_class_name$ : GPBRootObject |
|
|
|
|
@end |
|
|
|
|
|
|
|
|
|
$root_extensions$; |
|
|
|
|
$messages$; |
|
|
|
|
NS_ASSUME_NONNULL_END |
|
|
|
|
|
|
|
|
|
CF_EXTERN_C_END |
|
|
|
|
|
|
|
|
|
#pragma clang diagnostic pop |
|
|
|
|
|
|
|
|
|
// @@protoc_insertion_point(global_scope)
|
|
|
|
|
|
|
|
|
|
// $clangfmt$ on
|
|
|
|
|
)objc"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void FileGenerator::GenerateSource(io::Printer* printer) const { |
|
|
|
@ -455,7 +473,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) const { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
import_writer.Emit(printer); |
|
|
|
|
import_writer.EmitFileImports(printer); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool includes_oneof = false; |
|
|
|
@ -712,7 +730,8 @@ void FileGenerator::PrintFileRuntimePreamble( |
|
|
|
|
} else { |
|
|
|
|
ImportWriter::EmitRuntimeImports(printer, headers_to_import, |
|
|
|
|
generation_options_.runtime_import_prefix, |
|
|
|
|
true); |
|
|
|
|
/* is_bundled_proto = */ false, |
|
|
|
|
/* default_cpp_symbol = */ true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printer->Print("\n"); |
|
|
|
|