From bb4302e8787c3aa5226b5dab3b10750466deb828 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Mon, 28 Feb 2022 16:32:04 -0500 Subject: [PATCH] Add a generation option to control use of forward declarations in headers. Swift importing ObjC drops methods/properties if the type is only a forward declaration since the type is incomplete. Historically the generator has always use forward declarations to reduce how much will have rebuild when a proto file does change; but that puts it at odds with Swift. If ObjC Protos end up spanning Swift modules, the Swift import behavior could become a problem; so this option provides a control for the behavior. The current behavior is to continue forward declarations, but eventually the default will be changed. Generate the WKTs using imports instead of forward decls. --- objectivec/GPBApi.pbobjc.h | 5 +- objectivec/GPBApi.pbobjc.m | 2 - objectivec/GPBType.pbobjc.h | 4 +- objectivec/GPBType.pbobjc.m | 2 - objectivec/README.md | 17 ++++- .../objectivec/objectivec_enum_field.cc | 16 +++-- .../objectivec/objectivec_enum_field.h | 3 +- .../compiler/objectivec/objectivec_field.cc | 3 +- .../compiler/objectivec/objectivec_field.h | 3 +- .../compiler/objectivec/objectivec_file.cc | 65 ++++++++++++------- .../compiler/objectivec/objectivec_file.h | 6 +- .../objectivec/objectivec_generator.cc | 9 ++- .../objectivec/objectivec_map_field.cc | 14 +++- .../objectivec/objectivec_map_field.h | 3 +- .../compiler/objectivec/objectivec_message.cc | 7 +- .../compiler/objectivec/objectivec_message.h | 3 +- .../objectivec/objectivec_message_field.cc | 34 +++++++--- .../objectivec/objectivec_message_field.h | 6 +- 18 files changed, 140 insertions(+), 62 deletions(-) diff --git a/objectivec/GPBApi.pbobjc.h b/objectivec/GPBApi.pbobjc.h index 1634a9212ebb..871e90885a61 100644 --- a/objectivec/GPBApi.pbobjc.h +++ b/objectivec/GPBApi.pbobjc.h @@ -4,6 +4,8 @@ #import "GPBDescriptor.h" #import "GPBMessage.h" #import "GPBRootObject.h" +#import "GPBSourceContext.pbobjc.h" +#import "GPBType.pbobjc.h" #if GOOGLE_PROTOBUF_OBJC_VERSION < 30004 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. @@ -21,9 +23,6 @@ CF_EXTERN_C_BEGIN @class GPBMethod; @class GPBMixin; -@class GPBOption; -@class GPBSourceContext; -GPB_ENUM_FWD_DECLARE(GPBSyntax); NS_ASSUME_NONNULL_BEGIN diff --git a/objectivec/GPBApi.pbobjc.m b/objectivec/GPBApi.pbobjc.m index 639462b19d02..7f86a087ffd8 100644 --- a/objectivec/GPBApi.pbobjc.m +++ b/objectivec/GPBApi.pbobjc.m @@ -3,8 +3,6 @@ #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBApi.pbobjc.h" -#import "GPBSourceContext.pbobjc.h" -#import "GPBType.pbobjc.h" // @@protoc_insertion_point(imports) diff --git a/objectivec/GPBType.pbobjc.h b/objectivec/GPBType.pbobjc.h index ee02b0a6834d..b0230501cf3c 100644 --- a/objectivec/GPBType.pbobjc.h +++ b/objectivec/GPBType.pbobjc.h @@ -4,6 +4,8 @@ #import "GPBDescriptor.h" #import "GPBMessage.h" #import "GPBRootObject.h" +#import "GPBAny.pbobjc.h" +#import "GPBSourceContext.pbobjc.h" #if GOOGLE_PROTOBUF_OBJC_VERSION < 30004 #error This file was generated by a newer version of protoc which is incompatible with your Protocol Buffer library sources. @@ -19,11 +21,9 @@ CF_EXTERN_C_BEGIN -@class GPBAny; @class GPBEnumValue; @class GPBField; @class GPBOption; -@class GPBSourceContext; NS_ASSUME_NONNULL_BEGIN diff --git a/objectivec/GPBType.pbobjc.m b/objectivec/GPBType.pbobjc.m index 556df1971165..f5fc1efececb 100644 --- a/objectivec/GPBType.pbobjc.m +++ b/objectivec/GPBType.pbobjc.m @@ -3,8 +3,6 @@ #import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBType.pbobjc.h" -#import "GPBAny.pbobjc.h" -#import "GPBSourceContext.pbobjc.h" #import diff --git a/objectivec/README.md b/objectivec/README.md index 955fa531b715..a0fcd1930745 100644 --- a/objectivec/README.md +++ b/objectivec/README.md @@ -182,7 +182,7 @@ supported keys are: having to add the runtime directory to the header search path since the generate `#import` will be more complete. - * `package_to_prefix_mappings_path`: The `value` used for this key is a + * `package_to_prefix_mappings_path`: The `value` used for this key is a path to a file containing a list of proto packages and prefixes. The generator will use this to locate which ObjC class prefix to use when generating sources _unless_ the `objc_class_prefix` file option is set. @@ -218,6 +218,21 @@ supported keys are: helps prepare folks before they end up using a lot of protos and getting a lot of collisions. + * `headers_use_forward_declarations`: The `value` for this can be `yes` or + `no`, and indicates if the generated headers use forward declarations for + Message and Enum types from other .proto files or if the files should be + imported into the generated header instead. + + By using forward declarations, less code is likely to recompile when the + files do change, but Swift generally doesn't like forward declarations and + will fail to include properties when the concrete definition of the type is + known at import time. If your proto usages span modules, this can be a + problem. + + `headers_use_forward_declarations` currently defaults to `yes` (existing + behavior), but in a future release, that default may change to provide + better Swift support by default. + Contributing ------------ diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc index cdb208065e6d..1e55f3d95eec 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc @@ -115,12 +115,16 @@ void EnumFieldGenerator::GenerateCFunctionImplementations( } void EnumFieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls) const { - SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls); - // If it is an enum defined in a different file, then we'll need a forward - // declaration for it. When it is in our file, all the enums are output - // before the message, so it will be declared before it is needed. - if (descriptor_->file() != descriptor_->enum_type()->file()) { + std::set* fwd_decls, + bool include_external_types) const { + SingleFieldGenerator::DetermineForwardDeclarations( + fwd_decls, include_external_types); + // If it is an enum defined in a different file (and not a WKT), then we'll + // need a forward declaration for it. When it is in our file, all the enums + // are output before the message, so it will be declared before it is needed. + if (include_external_types && + descriptor_->file() != descriptor_->enum_type()->file() && + !IsProtobufLibraryBundledProtoFile(descriptor_->enum_type()->file())) { // Enum name is already in "storage_type". const std::string& name = variable("storage_type"); fwd_decls->insert("GPB_ENUM_FWD_DECLARE(" + name + ")"); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h index f89107e8574e..138be3114284 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h @@ -52,7 +52,8 @@ class EnumFieldGenerator : public SingleFieldGenerator { virtual void GenerateCFunctionImplementations( io::Printer* printer) const override; virtual void DetermineForwardDeclarations( - std::set* fwd_decls) const override; + std::set* fwd_decls, + bool include_external_types) const override; protected: EnumFieldGenerator(const FieldDescriptor* descriptor); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc index 2500f37dd0f2..f16dd4b9b697 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -183,7 +183,8 @@ void FieldGenerator::GenerateCFunctionImplementations( } void FieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls) const { + std::set* fwd_decls, + bool include_external_types) const { // Nothing } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h index c5080d6ba6d5..e1e906deff4e 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h @@ -64,7 +64,8 @@ class FieldGenerator { // Exposed for subclasses, should always call it on the parent class also. virtual void DetermineForwardDeclarations( - std::set* fwd_decls) const; + std::set* fwd_decls, + bool include_external_types) const; virtual void DetermineObjectiveCClassDefinitions( std::set* fwd_decls) const; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index 163639701d8f..84a75d83d5bc 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -57,6 +57,10 @@ const int32_t GOOGLE_PROTOBUF_OBJC_VERSION = 30004; const char* kHeaderExtension = ".pbobjc.h"; +std::string BundledFileName(const FileDescriptor* file) { + return "GPB" + FilePathBasename(file) + kHeaderExtension; +} + // Checks if a message contains any enums definitions (on the message or // a nested message under it). bool MessageContainsEnums(const Descriptor* message) { @@ -218,6 +222,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { 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"); } @@ -239,7 +247,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "\n", "google_protobuf_objc_version", StrCat(GOOGLE_PROTOBUF_OBJC_VERSION)); - // #import any headers for "public imports" in the proto file. + // 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, @@ -247,8 +258,15 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { generation_options_.runtime_import_prefix, /* include_wkt_imports = */ false); const std::string header_extension(kHeaderExtension); - for (int i = 0; i < file_->public_dependency_count(); i++) { - import_writer.AddFile(file_->public_dependency(i), header_extension); + 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.Print(printer); } @@ -268,7 +286,9 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { std::set fwd_decls; for (const auto& generator : message_generators_) { - generator->DetermineForwardDeclarations(&fwd_decls); + generator->DetermineForwardDeclarations( + &fwd_decls, + /* include_external_types = */ headers_use_forward_declarations); } for (std::set::const_iterator i(fwd_decls.begin()); i != fwd_decls.end(); ++i) { @@ -340,16 +360,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { void FileGenerator::GenerateSource(io::Printer* printer) { // #import the runtime support. - const std::string header_extension(kHeaderExtension); std::vector headers; headers.push_back("GPBProtocolBuffers_RuntimeSupport.h"); if (is_bundled_proto_) { - headers.push_back("GPB" + FilePathBasename(file_) + header_extension); - for (int i = 0; i < file_->dependency_count(); i++) { - const std::string header_name = - "GPB" + FilePathBasename(file_->dependency(i)) + header_extension; - headers.push_back(header_name); - } + headers.push_back(BundledFileName(file_)); } PrintFileRuntimePreamble(printer, headers); @@ -363,27 +377,34 @@ void FileGenerator::GenerateSource(io::Printer* printer) { std::vector deps_with_extensions; CollectMinimalFileDepsContainingExtensions(file_, &deps_with_extensions); + // 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); // #import the header for this proto file. import_writer.AddFile(file_, header_extension); - // #import the headers for anything that a plain dependency of this proto - // file (that means they were just an include, not a "public" include). - std::set 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); - bool public_import = (public_import_names.count(dep->name()) != 0); - if (!public_import) { - 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). + std::set 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); + bool public_import = (public_import_names.count(dep->name()) != 0); + if (!public_import) { + import_writer.AddFile(dep, header_extension); + } } } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.h b/src/google/protobuf/compiler/objectivec/objectivec_file.h index fc71c70c9dfc..64c833bd7f86 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.h @@ -49,10 +49,14 @@ class MessageGenerator; class FileGenerator { public: struct GenerationOptions { - GenerationOptions() {} + GenerationOptions() + // TODO(thomasvl): Eventually flip this default to false for better + // interop with Swift if proto usages span modules made from ObjC sources. + : headers_use_forward_declarations(true) {} std::string generate_for_named_framework; std::string named_framework_to_proto_path_mappings_path; std::string runtime_import_prefix; + bool headers_use_forward_declarations; }; FileGenerator(const FileDescriptor* file, diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc index e0279a1d2ef2..f61f34f465d3 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc @@ -189,8 +189,7 @@ bool ObjectiveCGenerator::GenerateAll( // generated files. When integrating ObjC protos into a build system, // this can be used to avoid having to add the runtime directory to the // header search path since the generate #import will be more complete. - generation_options.runtime_import_prefix = - StripSuffixString(options[i].second, "/"); + generation_options.runtime_import_prefix = StripSuffixString(options[i].second, "/"); } else if (options[i].first == "package_to_prefix_mappings_path") { // Path to use for when loading the objc class prefix mappings to use. // The `objc_class_prefix` file option is always honored first if one is present. @@ -231,6 +230,12 @@ bool ObjectiveCGenerator::GenerateAll( // - A comment can go on a line after a expected package/prefix pair. // (i.e. - "some.proto.package # comment") SetProtoPackagePrefixExceptionList(options[i].second); + } else if (options[i].first == "headers_use_forward_declarations") { + if (!StringToBool(options[i].second, + &generation_options.headers_use_forward_declarations)) { + *error = "error: Unknown value for headers_use_forward_declarations: " + options[i].second; + return false; + } } else { *error = "error: Unknown generator option: " + options[i].first; return false; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc index f6943cd9905a..99d7581533a2 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -160,11 +160,19 @@ void MapFieldGenerator::FinishInitialization(void) { } void MapFieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls) const { - RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); + std::set* fwd_decls, + bool include_external_types) const { + RepeatedFieldGenerator::DetermineForwardDeclarations( + fwd_decls, include_external_types); const FieldDescriptor* value_descriptor = descriptor_->message_type()->map_value(); - if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE) { + // Within a file there is no requirement on the order of the messages, so + // local references need a forward declaration. External files (not WKTs), + // need one when requested. + if (GetObjectiveCType(value_descriptor) == OBJECTIVECTYPE_MESSAGE && + ((include_external_types && + !IsProtobufLibraryBundledProtoFile(value_descriptor->file())) || + descriptor_->file() == value_descriptor->file())) { const std::string& value_storage_type = value_field_generator_->variable("storage_type"); fwd_decls->insert("@class " + value_storage_type); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h index c5b9b1df439c..36abf0e38c5c 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h @@ -56,7 +56,8 @@ class MapFieldGenerator : public RepeatedFieldGenerator { virtual void DetermineObjectiveCClassDefinitions( std::set* fwd_decls) const override; virtual void DetermineForwardDeclarations( - std::set* fwd_decls) const override; + std::set* fwd_decls, + bool include_external_types) const override; private: std::unique_ptr value_field_generator_; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc index 634b227d3f24..1cebdd339b98 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc @@ -215,17 +215,18 @@ void MessageGenerator::GenerateStaticVariablesInitialization( } void MessageGenerator::DetermineForwardDeclarations( - std::set* fwd_decls) { + std::set* fwd_decls, + bool include_external_types) { if (!IsMapEntryMessage(descriptor_)) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* fieldDescriptor = descriptor_->field(i); field_generators_.get(fieldDescriptor) - .DetermineForwardDeclarations(fwd_decls); + .DetermineForwardDeclarations(fwd_decls, include_external_types); } } for (const auto& generator : nested_message_generators_) { - generator->DetermineForwardDeclarations(fwd_decls); + generator->DetermineForwardDeclarations(fwd_decls, include_external_types); } } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.h b/src/google/protobuf/compiler/objectivec/objectivec_message.h index f53275181049..9d1443098181 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.h @@ -62,7 +62,8 @@ class MessageGenerator { void GenerateSource(io::Printer* printer); void GenerateExtensionRegistrationSource(io::Printer* printer); void DetermineObjectiveCClassDefinitions(std::set* fwd_decls); - void DetermineForwardDeclarations(std::set* fwd_decls); + void DetermineForwardDeclarations(std::set* fwd_decls, + bool include_external_types); // Checks if the message or a nested message includes a oneof definition. bool IncludesOneOfDefinition() const; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc index 437da524aeea..1aa61f126634 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc @@ -66,10 +66,19 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor) MessageFieldGenerator::~MessageFieldGenerator() {} void MessageFieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls) const { - ObjCObjFieldGenerator::DetermineForwardDeclarations(fwd_decls); - // Class name is already in "storage_type". - fwd_decls->insert("@class " + variable("storage_type")); + std::set* fwd_decls, + bool include_external_types) const { + ObjCObjFieldGenerator::DetermineForwardDeclarations( + fwd_decls, include_external_types); + // Within a file there is no requirement on the order of the messages, so + // local references need a forward declaration. External files (not WKTs), + // need one when requested. + if ((include_external_types && + !IsProtobufLibraryBundledProtoFile(descriptor_->message_type()->file())) || + descriptor_->file() == descriptor_->message_type()->file()) { + // Class name is already in "storage_type". + fwd_decls->insert("@class " + variable("storage_type")); + } } void MessageFieldGenerator::DetermineObjectiveCClassDefinitions( @@ -89,10 +98,19 @@ RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} void RepeatedMessageFieldGenerator::DetermineForwardDeclarations( - std::set* fwd_decls) const { - RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); - // Class name is already in "storage_type". - fwd_decls->insert("@class " + variable("storage_type")); + std::set* fwd_decls, + bool include_external_types) const { + RepeatedFieldGenerator::DetermineForwardDeclarations( + fwd_decls, include_external_types); + // Within a file there is no requirement on the order of the messages, so + // local references need a forward declaration. External files (not WKTs), + // need one when requested. + if ((include_external_types && + !IsProtobufLibraryBundledProtoFile(descriptor_->message_type()->file())) || + descriptor_->file() == descriptor_->message_type()->file()) { + // Class name is already in "storage_type". + fwd_decls->insert("@class " + variable("storage_type")); + } } void RepeatedMessageFieldGenerator::DetermineObjectiveCClassDefinitions( diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h index 1abf5c8ed5ad..bab150f86569 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_message_field.h @@ -53,7 +53,8 @@ class MessageFieldGenerator : public ObjCObjFieldGenerator { public: virtual void DetermineForwardDeclarations( - std::set* fwd_decls) const override; + std::set* fwd_decls, + bool include_external_types) const override; virtual void DetermineObjectiveCClassDefinitions( std::set* fwd_decls) const override; }; @@ -70,7 +71,8 @@ class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator { public: virtual void DetermineForwardDeclarations( - std::set* fwd_decls) const override; + std::set* fwd_decls, + bool include_external_types) const override; virtual void DetermineObjectiveCClassDefinitions( std::set* fwd_decls) const override; };