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));
+}
+