Skip to content

Commit bd9d689

Browse files
thomasvlcopybara-github
authored andcommitted
[ObjC] Add generation control for descriptor custom options.
There is a new boolean ObjC Generator Option called `strip_custom_options` that defaults to `True` that causes all extensions for the descriptor custom options to not generated. See https://protobuf.dev/programming-guides/proto2/#customoptions for more information on these. Since the ObjC runtime doesn't capture this data, we're not aware of any reason they would be need. If you do enable this option, please open an issue and let us know as we'd rather remove this option and have this be the only behavior. PiperOrigin-RevId: 556805883
1 parent 023b43d commit bd9d689

File tree

11 files changed

+115
-46
lines changed

11 files changed

+115
-46
lines changed

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

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
#include "google/protobuf/compiler/objectivec/field.h"
3232

33+
#include <cstddef>
3334
#include <string>
3435
#include <vector>
3536

@@ -447,16 +448,10 @@ void RepeatedFieldGenerator::EmitArrayComment(io::Printer* printer) const {
447448

448449
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor)
449450
: descriptor_(descriptor),
450-
field_generators_(descriptor->field_count()),
451-
extension_generators_(descriptor->extension_count()) {
452-
// Construct all the FieldGenerators.
451+
field_generators_(static_cast<size_t>(descriptor->field_count())) {
453452
for (int i = 0; i < descriptor->field_count(); i++) {
454453
field_generators_[i].reset(FieldGenerator::Make(descriptor->field(i)));
455454
}
456-
for (int i = 0; i < descriptor->extension_count(); i++) {
457-
extension_generators_[i].reset(
458-
FieldGenerator::Make(descriptor->extension(i)));
459-
}
460455
}
461456

462457
const FieldGenerator& FieldGeneratorMap::get(
@@ -465,10 +460,6 @@ const FieldGenerator& FieldGeneratorMap::get(
465460
return *field_generators_[field->index()];
466461
}
467462

468-
const FieldGenerator& FieldGeneratorMap::get_extension(int index) const {
469-
return *extension_generators_[index];
470-
}
471-
472463
int FieldGeneratorMap::CalculateHasBits() {
473464
int total_bits = 0;
474465
for (int i = 0; i < descriptor_->field_count(); i++) {

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ class FieldGeneratorMap {
172172
FieldGeneratorMap& operator=(const FieldGeneratorMap&) = delete;
173173

174174
const FieldGenerator& get(const FieldDescriptor* field) const;
175-
const FieldGenerator& get_extension(int index) const;
176175

177176
// Assigns the has bits and returns the number of bits needed.
178177
int CalculateHasBits();
@@ -185,7 +184,6 @@ class FieldGeneratorMap {
185184
private:
186185
const Descriptor* descriptor_;
187186
std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
188-
std::vector<std::unique_ptr<FieldGenerator>> extension_generators_;
189187
};
190188

191189
} // namespace objectivec

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

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include "google/protobuf/compiler/objectivec/file.h"
3232

3333
#include <algorithm>
34+
#include <cstddef>
35+
#include <cstdint>
3436
#include <functional>
3537
#include <iterator>
3638
#include <memory>
@@ -44,9 +46,11 @@
4446
#include "absl/strings/str_join.h"
4547
#include "google/protobuf/compiler/objectivec/enum.h"
4648
#include "google/protobuf/compiler/objectivec/extension.h"
49+
#include "google/protobuf/compiler/objectivec/helpers.h"
4750
#include "google/protobuf/compiler/objectivec/import_writer.h"
4851
#include "google/protobuf/compiler/objectivec/message.h"
4952
#include "google/protobuf/compiler/objectivec/names.h"
53+
#include "google/protobuf/compiler/objectivec/options.h"
5054
#include "google/protobuf/descriptor.h"
5155
#include "google/protobuf/descriptor.pb.h"
5256
#include "google/protobuf/descriptor_legacy.h"
@@ -64,28 +68,48 @@ const int32_t GOOGLE_PROTOBUF_OBJC_VERSION = 30007;
6468

6569
const char* kHeaderExtension = ".pbobjc.h";
6670

67-
// Checks if a message contains any extension definitions (on the message or
68-
// a nested message under it).
69-
bool MessageContainsExtensions(const Descriptor* message) {
71+
// Checks if a message contains extension definitions (on the message or
72+
// a nested message under it). `include_custom_options` decides if custom
73+
// options count as extensions.
74+
bool MessageContainsExtensions(const Descriptor* message,
75+
bool include_custom_options) {
7076
if (message->extension_count() > 0) {
71-
return true;
77+
if (include_custom_options) {
78+
return true;
79+
}
80+
for (int i = 0; i < message->extension_count(); i++) {
81+
if (!ExtensionIsCustomOption(message->extension(i))) {
82+
return true;
83+
}
84+
}
7285
}
7386
for (int i = 0; i < message->nested_type_count(); i++) {
74-
if (MessageContainsExtensions(message->nested_type(i))) {
87+
if (MessageContainsExtensions(message->nested_type(i),
88+
include_custom_options)) {
7589
return true;
7690
}
7791
}
7892
return false;
7993
}
8094

81-
// Checks if the file contains any extensions definitions (at the root or
82-
// nested under a message).
83-
bool FileContainsExtensions(const FileDescriptor* file) {
95+
// Checks if the file contains extensions definitions (at the root or
96+
// nested under a message). `include_custom_options` decides if custom
97+
// options count as extensions.
98+
bool FileContainsExtensions(const FileDescriptor* file,
99+
bool include_custom_options) {
84100
if (file->extension_count() > 0) {
85-
return true;
101+
if (include_custom_options) {
102+
return true;
103+
}
104+
for (int i = 0; i < file->extension_count(); i++) {
105+
if (!ExtensionIsCustomOption(file->extension(i))) {
106+
return true;
107+
}
108+
}
86109
}
87110
for (int i = 0; i < file->message_type_count(); i++) {
88-
if (MessageContainsExtensions(file->message_type(i))) {
111+
if (MessageContainsExtensions(file->message_type(i),
112+
include_custom_options)) {
89113
return true;
90114
}
91115
}
@@ -112,17 +136,20 @@ void MakeDescriptors(
112136
const Descriptor* descriptor, const std::string& file_description_name,
113137
std::vector<std::unique_ptr<EnumGenerator>>* enum_generators,
114138
std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators,
115-
std::vector<std::unique_ptr<MessageGenerator>>* message_generators) {
139+
std::vector<std::unique_ptr<MessageGenerator>>* message_generators,
140+
bool strip_custom_options) {
116141
for (int i = 0; i < descriptor->enum_type_count(); i++) {
117142
enum_generators->emplace_back(
118143
std::make_unique<EnumGenerator>(descriptor->enum_type(i)));
119144
}
120145
for (int i = 0; i < descriptor->nested_type_count(); i++) {
121146
message_generators->emplace_back(std::make_unique<MessageGenerator>(
122147
file_description_name, descriptor->nested_type(i)));
123-
message_generators->back()->AddExtensionGenerators(extension_generators);
148+
message_generators->back()->AddExtensionGenerators(extension_generators,
149+
strip_custom_options);
124150
MakeDescriptors(descriptor->nested_type(i), file_description_name,
125-
enum_generators, extension_generators, message_generators);
151+
enum_generators, extension_generators, message_generators,
152+
strip_custom_options);
126153
}
127154
}
128155

@@ -184,7 +211,8 @@ FileGenerator::CommonState::CollectMinimalFileDepsContainingExtensionsInternal(
184211
}
185212
}
186213

187-
const bool file_has_exts = FileContainsExtensions(file);
214+
const bool file_has_exts =
215+
FileContainsExtensions(file, include_custom_options);
188216

189217
// Fast path: if nothing to prune or there was only one dep, the prune work is
190218
// a waste, skip it.
@@ -241,16 +269,23 @@ FileGenerator::FileGenerator(const FileDescriptor* file,
241269
std::make_unique<EnumGenerator>(file_->enum_type(i)));
242270
}
243271
for (int i = 0; i < file_->extension_count(); i++) {
244-
extension_generators_.push_back(std::make_unique<ExtensionGenerator>(
245-
root_class_name_, file_->extension(i)));
272+
const FieldDescriptor* extension = file_->extension(i);
273+
if (!generation_options.strip_custom_options ||
274+
!ExtensionIsCustomOption(extension)) {
275+
extension_generators_.push_back(
276+
std::make_unique<ExtensionGenerator>(root_class_name_, extension));
277+
}
246278
}
279+
file_scoped_extension_count_ = extension_generators_.size();
247280
for (int i = 0; i < file_->message_type_count(); i++) {
248281
message_generators_.emplace_back(std::make_unique<MessageGenerator>(
249282
file_description_name_, file_->message_type(i)));
250-
message_generators_.back()->AddExtensionGenerators(&extension_generators_);
283+
message_generators_.back()->AddExtensionGenerators(
284+
&extension_generators_, generation_options.strip_custom_options);
251285
MakeDescriptors(file_->message_type(i), file_description_name_,
252286
&enum_generators_, &extension_generators_,
253-
&message_generators_);
287+
&message_generators_,
288+
generation_options.strip_custom_options);
254289
}
255290
}
256291

@@ -298,17 +333,17 @@ void FileGenerator::GenerateHeader(io::Printer* p) const {
298333

299334
// The dynamic methods block is only needed if there are extensions that are
300335
// file level scoped (not message scoped). The first
301-
// file_->extension_count() of extension_generators_ are the file scoped
336+
// file_scoped_extension_count_ of extension_generators_ are the file scoped
302337
// ones.
303-
if (file_->extension_count()) {
338+
if (file_scoped_extension_count_) {
304339
p->Emit("@interface $root_class_name$ (DynamicMethods)\n");
305340

306-
for (int i = 0; i < file_->extension_count(); i++) {
341+
for (size_t i = 0; i < file_scoped_extension_count_; i++) {
307342
extension_generators_[i]->GenerateMembersHeader(p);
308343
}
309344

310345
p->Emit("@end\n\n");
311-
} // file_->extension_count()
346+
}
312347

313348
for (const auto& generator : message_generators_) {
314349
generator->GenerateMessageHeader(p);

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
3232
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_FILE_H__
3333

34+
#include <cstddef>
3435
#include <functional>
3536
#include <memory>
3637
#include <string>
@@ -55,7 +56,10 @@ class FileGenerator {
5556
// Wrapper for some common state that is shared between file generations to
5657
// improve performance when more than one file is generated at a time.
5758
struct CommonState {
58-
CommonState() = default;
59+
// `include_custom_options` will cause any custom options to be included
60+
// in the calculations around files defining extensions.
61+
explicit CommonState(bool include_custom_options)
62+
: include_custom_options(include_custom_options) {}
5963

6064
std::vector<const FileDescriptor*>
6165
CollectMinimalFileDepsContainingExtensions(const FileDescriptor* file);
@@ -71,6 +75,7 @@ class FileGenerator {
7175
const MinDepsEntry& CollectMinimalFileDepsContainingExtensionsInternal(
7276
const FileDescriptor* file);
7377
absl::flat_hash_map<const FileDescriptor*, MinDepsEntry> deps_info_cache;
78+
const bool include_custom_options;
7479
};
7580

7681
FileGenerator(const FileDescriptor* file,
@@ -131,7 +136,10 @@ class FileGenerator {
131136

132137
std::vector<std::unique_ptr<EnumGenerator>> enum_generators_;
133138
std::vector<std::unique_ptr<MessageGenerator>> message_generators_;
134-
// The first file_->extension_count() are the extensions at file level scope.
139+
// The first file_scoped_extension_count_ are the extensions at file level
140+
// scope. This can be less than file_->extension_count() when custom options
141+
// are being filtered away.
142+
size_t file_scoped_extension_count_;
135143
std::vector<std::unique_ptr<ExtensionGenerator>> extension_generators_;
136144
};
137145

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

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,24 @@
3030

3131
#include "google/protobuf/compiler/objectivec/generator.h"
3232

33+
#include <cstddef>
34+
#include <cstdlib>
3335
#include <fstream>
34-
#include <iostream>
3536
#include <memory>
3637
#include <string>
3738
#include <utility>
3839
#include <vector>
3940

4041
#include "absl/container/flat_hash_set.h"
42+
#include "absl/memory/memory.h"
4143
#include "absl/strings/ascii.h"
4244
#include "absl/strings/str_cat.h"
4345
#include "absl/strings/str_split.h"
46+
#include "absl/strings/string_view.h"
4447
#include "absl/strings/strip.h"
4548
#include "google/protobuf/compiler/objectivec/file.h"
4649
#include "google/protobuf/compiler/objectivec/names.h"
50+
#include "google/protobuf/compiler/objectivec/options.h"
4751
#include "google/protobuf/io/printer.h"
4852
#include "google/protobuf/io/zero_copy_stream.h"
4953

@@ -258,6 +262,18 @@ bool ObjectiveCGenerator::GenerateAll(
258262
options[i].second);
259263
return false;
260264
}
265+
} else if (options[i].first == "strip_custom_options") {
266+
// Controls if extensions that define custom options are included the
267+
// generated code. Since ObjC protos does not capture these descriptor
268+
// options, there normally isn't a need for these extensions. Docs on
269+
// custom options:
270+
// https://protobuf.dev/programming-guides/proto2/#customoptions
271+
if (!StringToBool(options[i].second,
272+
&generation_options.strip_custom_options)) {
273+
*error = absl::StrCat("error: Unknown value for strip_custom_options: ",
274+
options[i].second);
275+
return false;
276+
}
261277
} else if (options[i].first == "experimental_multi_source_generation") {
262278
// This is an experimental option, and could be removed or change at any
263279
// time; it is not documented in the README.md for that reason.
@@ -314,7 +330,7 @@ bool ObjectiveCGenerator::GenerateAll(
314330
return false;
315331
}
316332

317-
FileGenerator::CommonState state;
333+
FileGenerator::CommonState state(!generation_options.strip_custom_options);
318334
for (const auto& file : files) {
319335
const FileGenerator file_generator(file, generation_options, state);
320336
std::string filepath = FilePath(file);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#ifndef GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
3434
#define GOOGLE_PROTOBUF_COMPILER_OBJECTIVEC_GENERATOR_H__
3535

36+
#include <cstdint>
3637
#include <string>
3738
#include <vector>
3839

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,15 @@ std::string HandleExtremeFloatingPoint(std::string val, bool add_float_suffix) {
105105
}
106106
}
107107

108+
const char* kDescriptorProtoName = "google/protobuf/descriptor.proto";
109+
108110
} // namespace
109111

112+
bool ExtensionIsCustomOption(const FieldDescriptor* extension_field) {
113+
return extension_field->containing_type()->file()->name() ==
114+
kDescriptorProtoName;
115+
}
116+
110117
std::string GetCapitalizedType(const FieldDescriptor* field) {
111118
switch (field->type()) {
112119
case FieldDescriptor::TYPE_INT32:

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

Lines changed: 5 additions & 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/string_view.h"
3940
#include "google/protobuf/descriptor.h"
4041
#include "google/protobuf/descriptor.pb.h"
4142
#include "google/protobuf/io/printer.h"
@@ -48,6 +49,10 @@ namespace objectivec {
4849
// Escape C++ trigraphs by escaping question marks to "\?".
4950
std::string EscapeTrigraphs(absl::string_view to_escape);
5051

52+
// Returns true if the extension field is a custom option.
53+
// https://protobuf.dev/programming-guides/proto2/#customoptions
54+
bool ExtensionIsCustomOption(const FieldDescriptor* extension_field);
55+
5156
enum ObjectiveCType {
5257
OBJECTIVECTYPE_INT32,
5358
OBJECTIVECTYPE_UINT32,

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,15 @@ MessageGenerator::MessageGenerator(const std::string& file_description_name,
253253
}
254254

255255
void MessageGenerator::AddExtensionGenerators(
256-
std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators) {
256+
std::vector<std::unique_ptr<ExtensionGenerator>>* extension_generators,
257+
bool strip_custom_options) {
257258
for (int i = 0; i < descriptor_->extension_count(); i++) {
258-
extension_generators->push_back(std::make_unique<ExtensionGenerator>(
259-
class_name_, descriptor_->extension(i)));
260-
extension_generators_.push_back(extension_generators->back().get());
259+
const FieldDescriptor* extension = descriptor_->extension(i);
260+
if (!strip_custom_options || !ExtensionIsCustomOption(extension)) {
261+
extension_generators->push_back(
262+
std::make_unique<ExtensionGenerator>(class_name_, extension));
263+
extension_generators_.push_back(extension_generators->back().get());
264+
}
261265
}
262266
}
263267

@@ -379,7 +383,7 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) const {
379383
printer->Emit("\n");
380384
}
381385

382-
if (descriptor_->extension_count() > 0) {
386+
if (!extension_generators_.empty()) {
383387
printer->Emit({{"extension_info",
384388
[&] {
385389
for (const auto* generator : extension_generators_) {
@@ -482,7 +486,7 @@ void MessageGenerator::GenerateSource(io::Printer* printer) const {
482486
// If the message scopes extensions, trigger the root class
483487
// +initialize/+extensionRegistry as that is where the
484488
// runtime support for extensions lives.
485-
if (descriptor_->extension_count() > 0) {
489+
if (!extension_generators_.empty()) {
486490
printer->Emit(R"objc(
487491
// Start up the root class to support the scoped extensions.
488492
__unused Class rootStartup = [$root_class_name$ class];

0 commit comments

Comments
 (0)