Add a helper for checking whether the descriptor pool has defaults for a particular language feature extension. PiperOrigin-RevId: 703549414
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 96130d1..575bb82 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc
@@ -33,6 +33,7 @@ #include <utility> #include <vector> +#include "absl/algorithm/container.h" #include "absl/base/attributes.h" #include "absl/base/call_once.h" #include "absl/base/casts.h" @@ -1102,20 +1103,6 @@ allowed_proto3_extendees->end(); } -const FeatureSetDefaults& GetCppFeatureSetDefaults() { - static const FeatureSetDefaults* default_spec = - internal::OnShutdownDelete([] { - auto* defaults = new FeatureSetDefaults(); - internal::ParseNoReflection( - absl::string_view{ - PROTOBUF_INTERNAL_CPP_EDITION_DEFAULTS, - sizeof(PROTOBUF_INTERNAL_CPP_EDITION_DEFAULTS) - 1}, - *defaults); - return defaults; - }()); - return *default_spec; -} - template <typename ProtoT> void RestoreFeaturesToOptions(const FeatureSet* features, ProtoT* proto) { if (features != &FeatureSet::default_instance()) { @@ -4789,6 +4776,36 @@ return absl::OkStatus(); } +const FeatureSetDefaults& DescriptorPool::GetFeatureSetDefaults() const { + if (feature_set_defaults_spec_ != nullptr) return *feature_set_defaults_spec_; + static const FeatureSetDefaults* cpp_default_spec = + internal::OnShutdownDelete([] { + auto* defaults = new FeatureSetDefaults(); + internal::ParseNoReflection( + absl::string_view{ + PROTOBUF_INTERNAL_CPP_EDITION_DEFAULTS, + sizeof(PROTOBUF_INTERNAL_CPP_EDITION_DEFAULTS) - 1}, + *defaults); + return defaults; + }()); + return *cpp_default_spec; +} + +bool DescriptorPool::ResolvesFeaturesForImpl(int extension_number) const { + for (const auto& edition_default : GetFeatureSetDefaults().defaults()) { + std::vector<const FieldDescriptor*> fields; + auto features = edition_default.fixed_features(); + features.MergeFrom(edition_default.overridable_features()); + features.GetReflection()->ListFields(features, &fields); + if (absl::c_find_if(fields, [&](const FieldDescriptor* field) { + return field->number() == extension_number; + }) == fields.end()) { + return false; + } + } + return true; +} + DescriptorBuilder::DescriptorBuilder( const DescriptorPool* pool, DescriptorPool::Tables* tables, DescriptorPool::DeferredValidation& deferred_validation, @@ -5921,10 +5938,7 @@ }); } - const FeatureSetDefaults& defaults = - pool_->feature_set_defaults_spec_ == nullptr - ? GetCppFeatureSetDefaults() - : *pool_->feature_set_defaults_spec_; + const FeatureSetDefaults& defaults = pool_->GetFeatureSetDefaults(); absl::StatusOr<FeatureResolver> feature_resolver = FeatureResolver::Create(file_->edition_, defaults);
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index d30a6ff..9e8bd68 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h
@@ -2274,6 +2274,15 @@ // be enforced while building proto files. absl::Status SetFeatureSetDefaults(FeatureSetDefaults spec); + // Returns true if the descriptor pool resolves features for the given + // extension. + template <typename TypeTraitsT, uint8_t field_type, bool is_packed> + bool ResolvesFeaturesFor( + const google::protobuf::internal::ExtensionIdentifier< + FeatureSet, TypeTraitsT, field_type, is_packed>& extension) const { + return ResolvesFeaturesForImpl(extension.number()); + } + // Toggles enforcement of extension declarations. // This enforcement is disabled by default because it requires full // descriptors with source-retention options, which are generally not @@ -2525,6 +2534,10 @@ bool IsReadyForCheckingDescriptorExtDecl( absl::string_view message_name) const; + + bool ResolvesFeaturesForImpl(int extension_number) const; + + const FeatureSetDefaults& GetFeatureSetDefaults() const; };
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 17eddae..cdfc4c3 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc
@@ -11678,6 +11678,24 @@ )pb")); } +TEST_F(DescriptorPoolFeaturesTest, ResolvesFeaturesForCppDefault) { + EXPECT_FALSE(pool_.ResolvesFeaturesFor(pb::test)); + EXPECT_FALSE(pool_.ResolvesFeaturesFor(pb::TestMessage::test_message)); + EXPECT_TRUE(pool_.ResolvesFeaturesFor(pb::cpp)); // The default. +} + +TEST_F(DescriptorPoolFeaturesTest, ResolvesFeaturesFor) { + auto test_default_spec = FeatureResolver::CompileDefaults( + FeatureSet::descriptor(), {GetExtensionReflection(pb::test)}, + EDITION_PROTO2, EDITION_99999_TEST_ONLY); + ASSERT_OK(test_default_spec); + ASSERT_OK(pool_.SetFeatureSetDefaults(std::move(test_default_spec).value())); + + EXPECT_TRUE(pool_.ResolvesFeaturesFor(pb::test)); + EXPECT_FALSE(pool_.ResolvesFeaturesFor(pb::TestMessage::test_message)); + EXPECT_FALSE(pool_.ResolvesFeaturesFor(pb::cpp)); +} +