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.
pull/9579/head
Thomas Van Lenten 3 years ago
parent 5f632bef38
commit bb4302e878
  1. 5
      objectivec/GPBApi.pbobjc.h
  2. 2
      objectivec/GPBApi.pbobjc.m
  3. 4
      objectivec/GPBType.pbobjc.h
  4. 2
      objectivec/GPBType.pbobjc.m
  5. 15
      objectivec/README.md
  6. 16
      src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc
  7. 3
      src/google/protobuf/compiler/objectivec/objectivec_enum_field.h
  8. 3
      src/google/protobuf/compiler/objectivec/objectivec_field.cc
  9. 3
      src/google/protobuf/compiler/objectivec/objectivec_field.h
  10. 39
      src/google/protobuf/compiler/objectivec/objectivec_file.cc
  11. 6
      src/google/protobuf/compiler/objectivec/objectivec_file.h
  12. 9
      src/google/protobuf/compiler/objectivec/objectivec_generator.cc
  13. 14
      src/google/protobuf/compiler/objectivec/objectivec_map_field.cc
  14. 3
      src/google/protobuf/compiler/objectivec/objectivec_map_field.h
  15. 7
      src/google/protobuf/compiler/objectivec/objectivec_message.cc
  16. 3
      src/google/protobuf/compiler/objectivec/objectivec_message.h
  17. 26
      src/google/protobuf/compiler/objectivec/objectivec_message_field.cc
  18. 6
      src/google/protobuf/compiler/objectivec/objectivec_message_field.h

@ -4,6 +4,8 @@
#import "GPBDescriptor.h" #import "GPBDescriptor.h"
#import "GPBMessage.h" #import "GPBMessage.h"
#import "GPBRootObject.h" #import "GPBRootObject.h"
#import "GPBSourceContext.pbobjc.h"
#import "GPBType.pbobjc.h"
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30004 #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. #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 GPBMethod;
@class GPBMixin; @class GPBMixin;
@class GPBOption;
@class GPBSourceContext;
GPB_ENUM_FWD_DECLARE(GPBSyntax);
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN

@ -3,8 +3,6 @@
#import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBApi.pbobjc.h" #import "GPBApi.pbobjc.h"
#import "GPBSourceContext.pbobjc.h"
#import "GPBType.pbobjc.h"
// @@protoc_insertion_point(imports) // @@protoc_insertion_point(imports)

@ -4,6 +4,8 @@
#import "GPBDescriptor.h" #import "GPBDescriptor.h"
#import "GPBMessage.h" #import "GPBMessage.h"
#import "GPBRootObject.h" #import "GPBRootObject.h"
#import "GPBAny.pbobjc.h"
#import "GPBSourceContext.pbobjc.h"
#if GOOGLE_PROTOBUF_OBJC_VERSION < 30004 #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. #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 CF_EXTERN_C_BEGIN
@class GPBAny;
@class GPBEnumValue; @class GPBEnumValue;
@class GPBField; @class GPBField;
@class GPBOption; @class GPBOption;
@class GPBSourceContext;
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN

@ -3,8 +3,6 @@
#import "GPBProtocolBuffers_RuntimeSupport.h" #import "GPBProtocolBuffers_RuntimeSupport.h"
#import "GPBType.pbobjc.h" #import "GPBType.pbobjc.h"
#import "GPBAny.pbobjc.h"
#import "GPBSourceContext.pbobjc.h"
#import <stdatomic.h> #import <stdatomic.h>

@ -218,6 +218,21 @@ supported keys are:
helps prepare folks before they end up using a lot of protos and getting a helps prepare folks before they end up using a lot of protos and getting a
lot of collisions. 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 Contributing
------------ ------------

@ -115,12 +115,16 @@ void EnumFieldGenerator::GenerateCFunctionImplementations(
} }
void EnumFieldGenerator::DetermineForwardDeclarations( void EnumFieldGenerator::DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const { std::set<std::string>* fwd_decls,
SingleFieldGenerator::DetermineForwardDeclarations(fwd_decls); bool include_external_types) const {
// If it is an enum defined in a different file, then we'll need a forward SingleFieldGenerator::DetermineForwardDeclarations(
// declaration for it. When it is in our file, all the enums are output fwd_decls, include_external_types);
// before the message, so it will be declared before it is needed. // If it is an enum defined in a different file (and not a WKT), then we'll
if (descriptor_->file() != descriptor_->enum_type()->file()) { // 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". // Enum name is already in "storage_type".
const std::string& name = variable("storage_type"); const std::string& name = variable("storage_type");
fwd_decls->insert("GPB_ENUM_FWD_DECLARE(" + name + ")"); fwd_decls->insert("GPB_ENUM_FWD_DECLARE(" + name + ")");

@ -52,7 +52,8 @@ class EnumFieldGenerator : public SingleFieldGenerator {
virtual void GenerateCFunctionImplementations( virtual void GenerateCFunctionImplementations(
io::Printer* printer) const override; io::Printer* printer) const override;
virtual void DetermineForwardDeclarations( virtual void DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const override; std::set<std::string>* fwd_decls,
bool include_external_types) const override;
protected: protected:
EnumFieldGenerator(const FieldDescriptor* descriptor); EnumFieldGenerator(const FieldDescriptor* descriptor);

@ -183,7 +183,8 @@ void FieldGenerator::GenerateCFunctionImplementations(
} }
void FieldGenerator::DetermineForwardDeclarations( void FieldGenerator::DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const { std::set<std::string>* fwd_decls,
bool include_external_types) const {
// Nothing // Nothing
} }

@ -64,7 +64,8 @@ class FieldGenerator {
// Exposed for subclasses, should always call it on the parent class also. // Exposed for subclasses, should always call it on the parent class also.
virtual void DetermineForwardDeclarations( virtual void DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const; std::set<std::string>* fwd_decls,
bool include_external_types) const;
virtual void DetermineObjectiveCClassDefinitions( virtual void DetermineObjectiveCClassDefinitions(
std::set<std::string>* fwd_decls) const; std::set<std::string>* fwd_decls) const;

@ -57,6 +57,10 @@ const int32_t GOOGLE_PROTOBUF_OBJC_VERSION = 30004;
const char* kHeaderExtension = ".pbobjc.h"; 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 // Checks if a message contains any enums definitions (on the message or
// a nested message under it). // a nested message under it).
bool MessageContainsEnums(const Descriptor* message) { bool MessageContainsEnums(const Descriptor* message) {
@ -218,6 +222,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
headers.push_back("GPBDescriptor.h"); headers.push_back("GPBDescriptor.h");
headers.push_back("GPBMessage.h"); headers.push_back("GPBMessage.h");
headers.push_back("GPBRootObject.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 { } else {
headers.push_back("GPBProtocolBuffers.h"); headers.push_back("GPBProtocolBuffers.h");
} }
@ -239,7 +247,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"\n", "\n",
"google_protobuf_objc_version", StrCat(GOOGLE_PROTOBUF_OBJC_VERSION)); "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( ImportWriter import_writer(
generation_options_.generate_for_named_framework, generation_options_.generate_for_named_framework,
@ -247,9 +258,16 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
generation_options_.runtime_import_prefix, generation_options_.runtime_import_prefix,
/* include_wkt_imports = */ false); /* include_wkt_imports = */ false);
const std::string header_extension(kHeaderExtension); 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++) { for (int i = 0; i < file_->public_dependency_count(); i++) {
import_writer.AddFile(file_->public_dependency(i), header_extension); 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); import_writer.Print(printer);
} }
@ -268,7 +286,9 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
std::set<std::string> fwd_decls; std::set<std::string> fwd_decls;
for (const auto& generator : message_generators_) { for (const auto& generator : message_generators_) {
generator->DetermineForwardDeclarations(&fwd_decls); generator->DetermineForwardDeclarations(
&fwd_decls,
/* include_external_types = */ headers_use_forward_declarations);
} }
for (std::set<std::string>::const_iterator i(fwd_decls.begin()); for (std::set<std::string>::const_iterator i(fwd_decls.begin());
i != fwd_decls.end(); ++i) { i != fwd_decls.end(); ++i) {
@ -340,16 +360,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
void FileGenerator::GenerateSource(io::Printer* printer) { void FileGenerator::GenerateSource(io::Printer* printer) {
// #import the runtime support. // #import the runtime support.
const std::string header_extension(kHeaderExtension);
std::vector<std::string> headers; std::vector<std::string> headers;
headers.push_back("GPBProtocolBuffers_RuntimeSupport.h"); headers.push_back("GPBProtocolBuffers_RuntimeSupport.h");
if (is_bundled_proto_) { if (is_bundled_proto_) {
headers.push_back("GPB" + FilePathBasename(file_) + header_extension); headers.push_back(BundledFileName(file_));
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);
}
} }
PrintFileRuntimePreamble(printer, headers); PrintFileRuntimePreamble(printer, headers);
@ -363,16 +377,22 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
std::vector<const FileDescriptor*> deps_with_extensions; std::vector<const FileDescriptor*> deps_with_extensions;
CollectMinimalFileDepsContainingExtensions(file_, &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( ImportWriter import_writer(
generation_options_.generate_for_named_framework, generation_options_.generate_for_named_framework,
generation_options_.named_framework_to_proto_path_mappings_path, generation_options_.named_framework_to_proto_path_mappings_path,
generation_options_.runtime_import_prefix, generation_options_.runtime_import_prefix,
/* include_wkt_imports = */ false); /* include_wkt_imports = */ false);
const std::string header_extension(kHeaderExtension);
// #import the header for this proto file. // #import the header for this proto file.
import_writer.AddFile(file_, header_extension); import_writer.AddFile(file_, header_extension);
if (headers_use_forward_declarations) {
// #import the headers for anything that a plain dependency of this proto // #import the headers for anything that a plain dependency of this proto
// file (that means they were just an include, not a "public" include). // file (that means they were just an include, not a "public" include).
std::set<std::string> public_import_names; std::set<std::string> public_import_names;
@ -386,6 +406,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
import_writer.AddFile(dep, header_extension); import_writer.AddFile(dep, header_extension);
} }
} }
}
// If any indirect dependency provided extensions, it needs to be directly // If any indirect dependency provided extensions, it needs to be directly
// imported so it can get merged into the root's extensions registry. // imported so it can get merged into the root's extensions registry.

@ -49,10 +49,14 @@ class MessageGenerator;
class FileGenerator { class FileGenerator {
public: public:
struct GenerationOptions { 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 generate_for_named_framework;
std::string named_framework_to_proto_path_mappings_path; std::string named_framework_to_proto_path_mappings_path;
std::string runtime_import_prefix; std::string runtime_import_prefix;
bool headers_use_forward_declarations;
}; };
FileGenerator(const FileDescriptor* file, FileGenerator(const FileDescriptor* file,

@ -189,8 +189,7 @@ bool ObjectiveCGenerator::GenerateAll(
// generated files. When integrating ObjC protos into a build system, // generated files. When integrating ObjC protos into a build system,
// this can be used to avoid having to add the runtime directory to the // 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. // header search path since the generate #import will be more complete.
generation_options.runtime_import_prefix = generation_options.runtime_import_prefix = StripSuffixString(options[i].second, "/");
StripSuffixString(options[i].second, "/");
} else if (options[i].first == "package_to_prefix_mappings_path") { } else if (options[i].first == "package_to_prefix_mappings_path") {
// Path to use for when loading the objc class prefix mappings to use. // 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. // 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. // - A comment can go on a line after a expected package/prefix pair.
// (i.e. - "some.proto.package # comment") // (i.e. - "some.proto.package # comment")
SetProtoPackagePrefixExceptionList(options[i].second); 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 { } else {
*error = "error: Unknown generator option: " + options[i].first; *error = "error: Unknown generator option: " + options[i].first;
return false; return false;

@ -160,11 +160,19 @@ void MapFieldGenerator::FinishInitialization(void) {
} }
void MapFieldGenerator::DetermineForwardDeclarations( void MapFieldGenerator::DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const { std::set<std::string>* fwd_decls,
RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); bool include_external_types) const {
RepeatedFieldGenerator::DetermineForwardDeclarations(
fwd_decls, include_external_types);
const FieldDescriptor* value_descriptor = const FieldDescriptor* value_descriptor =
descriptor_->message_type()->map_value(); 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 = const std::string& value_storage_type =
value_field_generator_->variable("storage_type"); value_field_generator_->variable("storage_type");
fwd_decls->insert("@class " + value_storage_type); fwd_decls->insert("@class " + value_storage_type);

@ -56,7 +56,8 @@ class MapFieldGenerator : public RepeatedFieldGenerator {
virtual void DetermineObjectiveCClassDefinitions( virtual void DetermineObjectiveCClassDefinitions(
std::set<std::string>* fwd_decls) const override; std::set<std::string>* fwd_decls) const override;
virtual void DetermineForwardDeclarations( virtual void DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const override; std::set<std::string>* fwd_decls,
bool include_external_types) const override;
private: private:
std::unique_ptr<FieldGenerator> value_field_generator_; std::unique_ptr<FieldGenerator> value_field_generator_;

@ -215,17 +215,18 @@ void MessageGenerator::GenerateStaticVariablesInitialization(
} }
void MessageGenerator::DetermineForwardDeclarations( void MessageGenerator::DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) { std::set<std::string>* fwd_decls,
bool include_external_types) {
if (!IsMapEntryMessage(descriptor_)) { if (!IsMapEntryMessage(descriptor_)) {
for (int i = 0; i < descriptor_->field_count(); i++) { for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* fieldDescriptor = descriptor_->field(i); const FieldDescriptor* fieldDescriptor = descriptor_->field(i);
field_generators_.get(fieldDescriptor) field_generators_.get(fieldDescriptor)
.DetermineForwardDeclarations(fwd_decls); .DetermineForwardDeclarations(fwd_decls, include_external_types);
} }
} }
for (const auto& generator : nested_message_generators_) { for (const auto& generator : nested_message_generators_) {
generator->DetermineForwardDeclarations(fwd_decls); generator->DetermineForwardDeclarations(fwd_decls, include_external_types);
} }
} }

@ -62,7 +62,8 @@ class MessageGenerator {
void GenerateSource(io::Printer* printer); void GenerateSource(io::Printer* printer);
void GenerateExtensionRegistrationSource(io::Printer* printer); void GenerateExtensionRegistrationSource(io::Printer* printer);
void DetermineObjectiveCClassDefinitions(std::set<std::string>* fwd_decls); void DetermineObjectiveCClassDefinitions(std::set<std::string>* fwd_decls);
void DetermineForwardDeclarations(std::set<std::string>* fwd_decls); void DetermineForwardDeclarations(std::set<std::string>* fwd_decls,
bool include_external_types);
// Checks if the message or a nested message includes a oneof definition. // Checks if the message or a nested message includes a oneof definition.
bool IncludesOneOfDefinition() const; bool IncludesOneOfDefinition() const;

@ -66,10 +66,19 @@ MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor)
MessageFieldGenerator::~MessageFieldGenerator() {} MessageFieldGenerator::~MessageFieldGenerator() {}
void MessageFieldGenerator::DetermineForwardDeclarations( void MessageFieldGenerator::DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const { std::set<std::string>* fwd_decls,
ObjCObjFieldGenerator::DetermineForwardDeclarations(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". // Class name is already in "storage_type".
fwd_decls->insert("@class " + variable("storage_type")); fwd_decls->insert("@class " + variable("storage_type"));
}
} }
void MessageFieldGenerator::DetermineObjectiveCClassDefinitions( void MessageFieldGenerator::DetermineObjectiveCClassDefinitions(
@ -89,10 +98,19 @@ RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
void RepeatedMessageFieldGenerator::DetermineForwardDeclarations( void RepeatedMessageFieldGenerator::DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const { std::set<std::string>* fwd_decls,
RepeatedFieldGenerator::DetermineForwardDeclarations(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". // Class name is already in "storage_type".
fwd_decls->insert("@class " + variable("storage_type")); fwd_decls->insert("@class " + variable("storage_type"));
}
} }
void RepeatedMessageFieldGenerator::DetermineObjectiveCClassDefinitions( void RepeatedMessageFieldGenerator::DetermineObjectiveCClassDefinitions(

@ -53,7 +53,8 @@ class MessageFieldGenerator : public ObjCObjFieldGenerator {
public: public:
virtual void DetermineForwardDeclarations( virtual void DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const override; std::set<std::string>* fwd_decls,
bool include_external_types) const override;
virtual void DetermineObjectiveCClassDefinitions( virtual void DetermineObjectiveCClassDefinitions(
std::set<std::string>* fwd_decls) const override; std::set<std::string>* fwd_decls) const override;
}; };
@ -70,7 +71,8 @@ class RepeatedMessageFieldGenerator : public RepeatedFieldGenerator {
public: public:
virtual void DetermineForwardDeclarations( virtual void DetermineForwardDeclarations(
std::set<std::string>* fwd_decls) const override; std::set<std::string>* fwd_decls,
bool include_external_types) const override;
virtual void DetermineObjectiveCClassDefinitions( virtual void DetermineObjectiveCClassDefinitions(
std::set<std::string>* fwd_decls) const override; std::set<std::string>* fwd_decls) const override;
}; };

Loading…
Cancel
Save