Skip to content

Commit 03223d0

Browse files
karenwuzcopybara-github
authored andcommitted
Generalizing and implementing ValidateFeatureSupport for both Options and Features during proto parsing
PiperOrigin-RevId: 838888348
1 parent 2504a29 commit 03223d0

File tree

7 files changed

+1061
-585
lines changed

7 files changed

+1061
-585
lines changed

src/google/protobuf/descriptor.cc

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,7 +1637,9 @@ class DescriptorPool::DeferredValidation {
16371637
}
16381638

16391639
bool Validate() {
1640-
if (lifetimes_info_map_.empty()) return true;
1640+
if (lifetimes_info_map_.empty()) {
1641+
return true;
1642+
}
16411643

16421644
static absl::string_view feature_set_name = "google.protobuf.FeatureSet";
16431645
const Descriptor* feature_set =
@@ -5014,6 +5016,9 @@ class DescriptorBuilder {
50145016
const DescriptorProto::ExtensionRange& proto) {}
50155017
void ValidateExtensionRangeOptions(const DescriptorProto& proto,
50165018
const Descriptor& message);
5019+
void ValidateFeatureSupport(
5020+
const FieldOptions::FeatureSupport& feature_support, const Message& proto,
5021+
absl::string_view full_name);
50175022
void ValidateExtensionDeclaration(
50185023
absl::string_view full_name,
50195024
const RepeatedPtrField<ExtensionRangeOptions_Declaration>& declarations,
@@ -8487,12 +8492,84 @@ void DescriptorBuilder::ValidateOptions(const OneofDescriptor* /*oneof*/,
84878492
}
84888493

84898494

8495+
void DescriptorBuilder::ValidateFeatureSupport(
8496+
const FieldOptions::FeatureSupport& feature_support, const Message& proto,
8497+
absl::string_view full_name) {
8498+
std::string feature_support_error(
8499+
FeatureResolver::ValidateFeatureSupport(feature_support, full_name)
8500+
.message());
8501+
if (!feature_support_error.empty()) {
8502+
AddError(full_name, proto, DescriptorPool::ErrorCollector::OPTION_NAME,
8503+
feature_support_error.c_str());
8504+
}
8505+
}
8506+
84908507
void DescriptorBuilder::ValidateOptions(const FieldDescriptor* field,
84918508
const FieldDescriptorProto& proto) {
84928509
if (pool_->lazily_build_dependencies_ && (!field || !field->message_type())) {
84938510
return;
84948511
}
8512+
if (field->options().has_feature_support()) {
8513+
const FieldOptions::FeatureSupport field_feature_support =
8514+
field->options().feature_support();
8515+
ValidateFeatureSupport(field_feature_support, proto, field->full_name());
8516+
if (field->enum_type() != nullptr) {
8517+
for (int i = 0; i < field->enum_type()->value_count(); i++) {
8518+
const EnumValueDescriptor& value = *field->enum_type()->value(i);
8519+
// We allow missing support windows on feature values, and they'll
8520+
// inherit from the feature spec.
8521+
if (!value.options().has_feature_support()) {
8522+
continue;
8523+
}
84958524

8525+
FieldOptions::FeatureSupport value_feature_support =
8526+
field_feature_support;
8527+
value_feature_support.MergeFrom(value.options().feature_support());
8528+
ValidateFeatureSupport(value_feature_support, proto, value.full_name());
8529+
8530+
// Make sure enum values don't expand any bounds
8531+
if (field_feature_support.edition_introduced() >
8532+
value_feature_support.edition_introduced()) {
8533+
AddError(value.full_name(), proto,
8534+
DescriptorPool::ErrorCollector::OPTION_NAME,
8535+
absl::Substitute("value $0 was introduced before $1 was.",
8536+
value.full_name(), field->full_name())
8537+
.c_str());
8538+
}
8539+
if (field_feature_support.has_edition_removed() &&
8540+
field_feature_support.edition_removed() <
8541+
value_feature_support.edition_removed()) {
8542+
AddError(value.full_name(), proto,
8543+
DescriptorPool::ErrorCollector::OPTION_NAME,
8544+
absl::Substitute("value $0 was removed after $1 was.",
8545+
value.full_name(), field->full_name())
8546+
.c_str());
8547+
}
8548+
if (field_feature_support.has_edition_deprecated() &&
8549+
field_feature_support.edition_deprecated() <
8550+
value_feature_support.edition_deprecated()) {
8551+
AddError(value.full_name(), proto,
8552+
DescriptorPool::ErrorCollector::OPTION_NAME,
8553+
absl::Substitute("value $0 was deprecated after $1 was.",
8554+
value.full_name(), field->full_name())
8555+
.c_str());
8556+
}
8557+
}
8558+
}
8559+
} else if (field->enum_type() != nullptr) {
8560+
for (int i = 0; i < field->enum_type()->value_count(); i++) {
8561+
const EnumValueDescriptor& value = *field->enum_type()->value(i);
8562+
if (value.options().has_feature_support()) {
8563+
AddError(value.full_name(), proto,
8564+
DescriptorPool::ErrorCollector::OPTION_NAME,
8565+
absl::Substitute(
8566+
"value $0 is not allowed to have feature support "
8567+
"because its field $1 doesn't have feature support.",
8568+
value.full_name(), field->full_name())
8569+
.c_str());
8570+
}
8571+
}
8572+
}
84968573
ValidateFieldFeatures(field, proto);
84978574

84988575

@@ -8822,10 +8899,12 @@ void DescriptorBuilder::ValidateOptions(const EnumDescriptor* enm,
88228899
}
88238900
}
88248901

8825-
void DescriptorBuilder::ValidateOptions(
8826-
const EnumValueDescriptor* /* enum_value */,
8827-
const EnumValueDescriptorProto& /* proto */) {
8828-
// Nothing to do so far.
8902+
void DescriptorBuilder::ValidateOptions(const EnumValueDescriptor* enum_value,
8903+
const EnumValueDescriptorProto& proto) {
8904+
if (enum_value->options().has_feature_support()) {
8905+
ValidateFeatureSupport(enum_value->options().feature_support(), proto,
8906+
enum_value->full_name());
8907+
}
88298908
}
88308909

88318910
namespace {

0 commit comments

Comments
 (0)