Skip to content

Commit 0b817d4

Browse files
thomasvlcopybara-github
authored andcommitted
[ObjC] add "generate_minimal_imports" generation option
This new option will cause only the files that provide types to be imported into the generated code. This helps reduce the inputs that aren't needed (folks ignoring the protoc warnings) and for things imported only for custom options as the objc generated code doesn't capture those and thus the imports aren't needed in the generated code. Also do some general import cleanups. PiperOrigin-RevId: 558867748
1 parent 230232a commit 0b817d4

File tree

17 files changed

+213
-13
lines changed

17 files changed

+213
-13
lines changed

src/google/protobuf/compiler/objectivec/enum_field.cc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,14 @@
3232

3333
#include <string>
3434

35+
#include "absl/container/btree_set.h"
3536
#include "absl/container/flat_hash_map.h"
37+
#include "absl/container/flat_hash_set.h"
38+
#include "absl/strings/str_cat.h"
39+
#include "absl/strings/string_view.h"
40+
#include "google/protobuf/compiler/objectivec/field.h"
3641
#include "google/protobuf/compiler/objectivec/names.h"
42+
#include "google/protobuf/descriptor.h"
3743
#include "google/protobuf/io/printer.h"
3844

3945
namespace google {
@@ -135,6 +141,13 @@ void EnumFieldGenerator::DetermineForwardDeclarations(
135141
}
136142
}
137143

144+
void EnumFieldGenerator::DetermineNeededFiles(
145+
absl::flat_hash_set<const FileDescriptor*>* deps) const {
146+
if (descriptor_->file() != descriptor_->enum_type()->file()) {
147+
deps->insert(descriptor_->enum_type()->file());
148+
}
149+
}
150+
138151
RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
139152
const FieldDescriptor* descriptor)
140153
: RepeatedFieldGenerator(descriptor) {
@@ -153,6 +166,13 @@ void RepeatedEnumFieldGenerator::EmitArrayComment(io::Printer* printer) const {
153166
// because `GPBEnumArray` isn't generic (like `NSArray` would be for messages)
154167
// and thus doesn't reference the type in the header.
155168

169+
void RepeatedEnumFieldGenerator::DetermineNeededFiles(
170+
absl::flat_hash_set<const FileDescriptor*>* deps) const {
171+
if (descriptor_->file() != descriptor_->enum_type()->file()) {
172+
deps->insert(descriptor_->enum_type()->file());
173+
}
174+
}
175+
156176
} // namespace objectivec
157177
} // namespace compiler
158178
} // namespace protobuf

src/google/protobuf/compiler/objectivec/enum_field.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
#include <string>
3535

3636
#include "absl/container/btree_set.h"
37+
#include "absl/container/flat_hash_set.h"
3738
#include "google/protobuf/compiler/objectivec/field.h"
39+
#include "google/protobuf/descriptor.h"
3840

3941
namespace google {
4042
namespace protobuf {
@@ -52,6 +54,8 @@ class EnumFieldGenerator : public SingleFieldGenerator {
5254
void GenerateCFunctionImplementations(io::Printer* printer) const override;
5355
void DetermineForwardDeclarations(absl::btree_set<std::string>* fwd_decls,
5456
bool include_external_types) const override;
57+
void DetermineNeededFiles(
58+
absl::flat_hash_set<const FileDescriptor*>* deps) const override;
5559

5660
protected:
5761
explicit EnumFieldGenerator(const FieldDescriptor* descriptor);
@@ -63,6 +67,8 @@ class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator {
6367

6468
public:
6569
void EmitArrayComment(io::Printer* printer) const override;
70+
void DetermineNeededFiles(
71+
absl::flat_hash_set<const FileDescriptor*>* deps) const override;
6672

6773
protected:
6874
explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor);

src/google/protobuf/compiler/objectivec/extension.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@
3434
#include <vector>
3535

3636
#include "absl/container/btree_set.h"
37+
#include "absl/container/flat_hash_set.h"
38+
#include "absl/log/absl_check.h"
3739
#include "absl/strings/str_cat.h"
40+
#include "absl/strings/string_view.h"
3841
#include "google/protobuf/compiler/objectivec/helpers.h"
3942
#include "google/protobuf/compiler/objectivec/names.h"
43+
#include "google/protobuf/descriptor.h"
4044
#include "google/protobuf/descriptor.pb.h"
4145
#include "google/protobuf/io/printer.h"
4246

@@ -128,6 +132,27 @@ void ExtensionGenerator::DetermineObjectiveCClassDefinitions(
128132
}
129133
}
130134

135+
void ExtensionGenerator::DetermineNeededFiles(
136+
absl::flat_hash_set<const FileDescriptor*>* deps) const {
137+
const Descriptor* extended_type = descriptor_->containing_type();
138+
if (descriptor_->file() != extended_type->file()) {
139+
deps->insert(extended_type->file());
140+
}
141+
142+
const ObjectiveCType objc_type = GetObjectiveCType(descriptor_);
143+
if (objc_type == OBJECTIVECTYPE_MESSAGE) {
144+
const Descriptor* value_msg_descriptor = descriptor_->message_type();
145+
if (descriptor_->file() != value_msg_descriptor->file()) {
146+
deps->insert(value_msg_descriptor->file());
147+
}
148+
} else if (objc_type == OBJECTIVECTYPE_ENUM) {
149+
const EnumDescriptor* value_enum_descriptor = descriptor_->enum_type();
150+
if (descriptor_->file() != value_enum_descriptor->file()) {
151+
deps->insert(value_enum_descriptor->file());
152+
}
153+
}
154+
}
155+
131156
void ExtensionGenerator::GenerateRegistrationSource(
132157
io::Printer* printer) const {
133158
printer->Emit({{"full_method_name", full_method_name_}},

src/google/protobuf/compiler/objectivec/extension.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include <string>
3535

3636
#include "absl/container/btree_set.h"
37+
#include "absl/container/flat_hash_set.h"
38+
#include "absl/strings/string_view.h"
3739
#include "google/protobuf/descriptor.h"
3840
#include "google/protobuf/io/printer.h"
3941

@@ -56,6 +58,8 @@ class ExtensionGenerator {
5658
void GenerateRegistrationSource(io::Printer* printer) const;
5759
void DetermineObjectiveCClassDefinitions(
5860
absl::btree_set<std::string>* fwd_decls) const;
61+
void DetermineNeededFiles(
62+
absl::flat_hash_set<const FileDescriptor*>* deps) const;
5963

6064
private:
6165
std::string method_name_;

src/google/protobuf/compiler/objectivec/field.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,20 @@
3434
#include <string>
3535
#include <vector>
3636

37+
#include "absl/container/btree_set.h"
3738
#include "absl/container/flat_hash_map.h"
39+
#include "absl/container/flat_hash_set.h"
3840
#include "absl/log/absl_check.h"
3941
#include "absl/log/absl_log.h"
4042
#include "absl/strings/str_cat.h"
43+
#include "absl/strings/string_view.h"
4144
#include "google/protobuf/compiler/objectivec/enum_field.h"
4245
#include "google/protobuf/compiler/objectivec/helpers.h"
4346
#include "google/protobuf/compiler/objectivec/map_field.h"
4447
#include "google/protobuf/compiler/objectivec/message_field.h"
4548
#include "google/protobuf/compiler/objectivec/names.h"
4649
#include "google/protobuf/compiler/objectivec/primitive_field.h"
50+
#include "google/protobuf/descriptor.h"
4751
#include "google/protobuf/io/printer.h"
4852

4953
namespace google {
@@ -237,6 +241,11 @@ void FieldGenerator::DetermineObjectiveCClassDefinitions(
237241
// Nothing
238242
}
239243

244+
void FieldGenerator::DetermineNeededFiles(
245+
absl::flat_hash_set<const FileDescriptor*>* deps) const {
246+
// Nothing
247+
}
248+
240249
void FieldGenerator::GenerateFieldDescription(io::Printer* printer,
241250
bool include_default) const {
242251
// Printed in the same order as the structure decl.

src/google/protobuf/compiler/objectivec/field.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@
3737

3838
#include "absl/container/btree_set.h"
3939
#include "absl/container/flat_hash_map.h"
40+
#include "absl/container/flat_hash_set.h"
4041
#include "absl/strings/match.h"
42+
#include "absl/strings/string_view.h"
4143
#include "google/protobuf/descriptor.h"
4244
#include "google/protobuf/io/printer.h"
4345

@@ -73,6 +75,8 @@ class FieldGenerator {
7375
bool include_external_types) const;
7476
virtual void DetermineObjectiveCClassDefinitions(
7577
absl::btree_set<std::string>* fwd_decls) const;
78+
virtual void DetermineNeededFiles(
79+
absl::flat_hash_set<const FileDescriptor*>* deps) const;
7680

7781
// Used during generation, not intended to be extended by subclasses.
7882
void GenerateFieldDescription(io::Printer* printer,

src/google/protobuf/compiler/objectivec/file.cc

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ void FileGenerator::GenerateFile(io::Printer* p, GeneratedFileType file_type,
486486
/* for_bundled_proto = */ is_bundled_proto_);
487487
const std::string header_extension(kHeaderExtension);
488488

489+
absl::flat_hash_set<const FileDescriptor*> file_imports;
489490
switch (file_type) {
490491
case GeneratedFileType::kHeader:
491492
// Generated files bundled with the library get minimal imports,
@@ -500,35 +501,50 @@ void FileGenerator::GenerateFile(io::Printer* p, GeneratedFileType file_type,
500501
if (HeadersUseForwardDeclarations()) {
501502
// #import any headers for "public imports" in the proto file.
502503
for (int i = 0; i < file_->public_dependency_count(); i++) {
503-
import_writer.AddFile(file_->public_dependency(i), header_extension);
504+
file_imports.insert(file_->public_dependency(i));
504505
}
506+
} else if (generation_options_.generate_minimal_imports) {
507+
DetermineNeededDeps(&file_imports, PublicDepsHandling::kForceInclude);
505508
} else {
506509
for (int i = 0; i < file_->dependency_count(); i++) {
507-
import_writer.AddFile(file_->dependency(i), header_extension);
510+
file_imports.insert(file_->dependency(i));
508511
}
509512
}
510513
break;
511514
case GeneratedFileType::kSource:
512515
import_writer.AddRuntimeImport("GPBProtocolBuffers_RuntimeSupport.h");
513516
import_writer.AddFile(file_, header_extension);
514517
if (HeadersUseForwardDeclarations()) {
515-
// #import the headers for anything that a plain dependency of this
516-
// proto file (that means they were just an include, not a "public"
517-
// include).
518-
absl::flat_hash_set<std::string> public_import_names;
519-
for (int i = 0; i < file_->public_dependency_count(); i++) {
520-
public_import_names.insert(file_->public_dependency(i)->name());
521-
}
522-
for (int i = 0; i < file_->dependency_count(); i++) {
523-
const FileDescriptor* dep = file_->dependency(i);
524-
if (!public_import_names.contains(dep->name())) {
525-
import_writer.AddFile(dep, header_extension);
518+
if (generation_options_.generate_minimal_imports) {
519+
DetermineNeededDeps(&file_imports, PublicDepsHandling::kExclude);
520+
} else {
521+
// #import the headers for anything that a plain dependency of this
522+
// proto file (that means they were just an include, not a "public"
523+
// include).
524+
absl::flat_hash_set<std::string> public_import_names;
525+
for (int i = 0; i < file_->public_dependency_count(); i++) {
526+
public_import_names.insert(file_->public_dependency(i)->name());
527+
}
528+
for (int i = 0; i < file_->dependency_count(); i++) {
529+
const FileDescriptor* dep = file_->dependency(i);
530+
if (!public_import_names.contains(dep->name())) {
531+
file_imports.insert(dep);
532+
}
526533
}
527534
}
528535
}
529536
break;
530537
}
531538

539+
if (!file_imports.empty()) {
540+
for (int i = 0; i < file_->dependency_count(); i++) {
541+
const FileDescriptor* dep = file_->dependency(i);
542+
if (file_imports.contains(dep)) {
543+
import_writer.AddFile(file_->dependency(i), header_extension);
544+
}
545+
}
546+
}
547+
532548
for (const auto& dep : file_options.extra_files_to_import) {
533549
import_writer.AddFile(dep, header_extension);
534550
}
@@ -752,6 +768,34 @@ void FileGenerator::EmitFileDescription(io::Printer* p) const {
752768
p->Emit("\n");
753769
}
754770

771+
void FileGenerator::DetermineNeededDeps(
772+
absl::flat_hash_set<const FileDescriptor*>* deps,
773+
PublicDepsHandling public_deps_handling) const {
774+
// This logic captures the deps that are needed for types thus removing the
775+
// ones that are only deps because they provide the definitions for custom
776+
// options. If protoc gets something like "import options" then this logic can
777+
// go away as the non "import options" deps would be the ones needed.
778+
779+
if (public_deps_handling == PublicDepsHandling::kForceInclude) {
780+
for (int i = 0; i < file_->public_dependency_count(); i++) {
781+
deps->insert(file_->public_dependency(i));
782+
}
783+
}
784+
785+
for (const auto& generator : message_generators_) {
786+
generator->DetermineNeededFiles(deps);
787+
}
788+
for (const auto& generator : extension_generators_) {
789+
generator->DetermineNeededFiles(deps);
790+
}
791+
792+
if (public_deps_handling == PublicDepsHandling::kExclude) {
793+
for (int i = 0; i < file_->public_dependency_count(); i++) {
794+
deps->erase(file_);
795+
}
796+
}
797+
}
798+
755799
} // namespace objectivec
756800
} // namespace compiler
757801
} // namespace protobuf

src/google/protobuf/compiler/objectivec/file.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ class FileGenerator {
121121
const std::vector<const FileDescriptor*>& deps_with_extensions) const;
122122
void EmitFileDescription(io::Printer* p) const;
123123

124+
enum class PublicDepsHandling : int { kAsUsed, kForceInclude, kExclude };
125+
void DetermineNeededDeps(absl::flat_hash_set<const FileDescriptor*>* deps,
126+
PublicDepsHandling public_deps_handling) const;
127+
124128
bool HeadersUseForwardDeclarations() const {
125129
// The bundled protos (WKTs) don't make use of forward declarations.
126130
return !is_bundled_proto_ &&

src/google/protobuf/compiler/objectivec/generator.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,18 @@ bool ObjectiveCGenerator::GenerateAll(
274274
options[i].second);
275275
return false;
276276
}
277+
} else if (options[i].first == "generate_minimal_imports") {
278+
// Controls if minimal imports should be generated from a files imports.
279+
// Since custom options require imports, they current cause generated
280+
// imports even though there is nothing captured in the generated code,
281+
// this provides smaller imports only for the things referenced.
282+
if (!StringToBool(options[i].second,
283+
&generation_options.generate_minimal_imports)) {
284+
*error =
285+
absl::StrCat("error: Unknown value for generate_minimal_imports: ",
286+
options[i].second);
287+
return false;
288+
}
277289
} else if (options[i].first == "experimental_multi_source_generation") {
278290
// This is an experimental option, and could be removed or change at any
279291
// time; it is not documented in the README.md for that reason.

src/google/protobuf/compiler/objectivec/helpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <string>
3737
#include <vector>
3838

39+
#include "absl/strings/str_cat.h"
3940
#include "absl/strings/string_view.h"
4041
#include "google/protobuf/descriptor.h"
4142
#include "google/protobuf/descriptor.pb.h"

0 commit comments

Comments
 (0)