|
|
|
@ -55,7 +55,6 @@ |
|
|
|
|
#include "google/protobuf/cpp_features.pb.h" |
|
|
|
|
#include "google/protobuf/descriptor.pb.h" |
|
|
|
|
#include "google/protobuf/descriptor_database.h" |
|
|
|
|
#include "google/protobuf/descriptor_legacy.h" |
|
|
|
|
#include "google/protobuf/descriptor_visitor.h" |
|
|
|
|
#include "google/protobuf/dynamic_message.h" |
|
|
|
|
#include "google/protobuf/feature_resolver.h" |
|
|
|
@ -811,7 +810,6 @@ const char* const FieldDescriptor::kLabelToName[MAX_LABEL + 1] = { |
|
|
|
|
"repeated", // LABEL_REPEATED
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
PROTOBUF_IGNORE_DEPRECATION_START |
|
|
|
|
const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) { |
|
|
|
|
switch (syntax) { |
|
|
|
|
case SYNTAX_PROTO2: |
|
|
|
@ -826,7 +824,6 @@ const char* FileDescriptor::SyntaxName(FileDescriptor::Syntax syntax) { |
|
|
|
|
ABSL_LOG(FATAL) << "can't reach here."; |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
PROTOBUF_IGNORE_DEPRECATION_STOP |
|
|
|
|
|
|
|
|
|
static const char* const kNonLinkedWeakMessageReplacementName = "google.protobuf.Empty"; |
|
|
|
|
|
|
|
|
@ -1181,6 +1178,25 @@ const FeatureSet& GetParentFeatures(const ServiceDescriptor* service) { |
|
|
|
|
const FeatureSet& GetParentFeatures(const MethodDescriptor* method) { |
|
|
|
|
return internal::InternalFeatureHelper::GetFeatures(*method->service()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool IsLegacyEdition(const FileDescriptor* file) { |
|
|
|
|
return file->edition() < Edition::EDITION_2023; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <class DescriptorT> |
|
|
|
|
bool IsLegacyEdition(const DescriptorT* descriptor) { |
|
|
|
|
return IsLegacyEdition(descriptor->file()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Edition GetDescriptorEdition(const FileDescriptor* descriptor) { |
|
|
|
|
return descriptor->edition(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <class DescriptorT> |
|
|
|
|
Edition GetDescriptorEdition(const DescriptorT* descriptor) { |
|
|
|
|
return GetDescriptorEdition(descriptor->file()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
|
|
// Contains tables specific to a particular file. These tables are not
|
|
|
|
@ -2755,13 +2771,10 @@ void FileDescriptor::CopyHeadingTo(FileDescriptorProto* proto) const { |
|
|
|
|
proto->set_package(package()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// TODO: Also populate when syntax="proto2".
|
|
|
|
|
FileDescriptorLegacy::Syntax syntax = FileDescriptorLegacy(this).syntax(); |
|
|
|
|
if (syntax == FileDescriptorLegacy::Syntax::SYNTAX_PROTO3 || |
|
|
|
|
syntax == FileDescriptorLegacy::Syntax::SYNTAX_EDITIONS) { |
|
|
|
|
proto->set_syntax(FileDescriptorLegacy::SyntaxName(syntax)); |
|
|
|
|
} |
|
|
|
|
if (syntax == FileDescriptorLegacy::Syntax::SYNTAX_EDITIONS) { |
|
|
|
|
if (edition() == Edition::EDITION_PROTO3) { |
|
|
|
|
proto->set_syntax("proto3"); |
|
|
|
|
} else if (!IsLegacyEdition(this)) { |
|
|
|
|
proto->set_syntax("editions"); |
|
|
|
|
proto->set_edition(edition()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -2858,8 +2871,7 @@ void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const { |
|
|
|
|
} |
|
|
|
|
// Some compilers do not allow static_cast directly between two enum types,
|
|
|
|
|
// so we must cast to int first.
|
|
|
|
|
if (is_required() && FileDescriptorLegacy(file()).syntax() == |
|
|
|
|
FileDescriptorLegacy::Syntax::SYNTAX_EDITIONS) { |
|
|
|
|
if (is_required() && !IsLegacyEdition(this)) { |
|
|
|
|
// Editions files have no required keyword, and we only set this label
|
|
|
|
|
// during descriptor build.
|
|
|
|
|
proto->set_label(static_cast<FieldDescriptorProto::Label>( |
|
|
|
@ -2868,9 +2880,7 @@ void FieldDescriptor::CopyTo(FieldDescriptorProto* proto) const { |
|
|
|
|
proto->set_label(static_cast<FieldDescriptorProto::Label>( |
|
|
|
|
absl::implicit_cast<int>(label()))); |
|
|
|
|
} |
|
|
|
|
if (type() == TYPE_GROUP && |
|
|
|
|
FileDescriptorLegacy(file()).syntax() == |
|
|
|
|
FileDescriptorLegacy::Syntax::SYNTAX_EDITIONS) { |
|
|
|
|
if (type() == TYPE_GROUP && !IsLegacyEdition(this)) { |
|
|
|
|
// Editions files have no group keyword, and we only set this label
|
|
|
|
|
// during descriptor build.
|
|
|
|
|
proto->set_type(static_cast<FieldDescriptorProto::Type>( |
|
|
|
@ -3007,11 +3017,7 @@ void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const { |
|
|
|
|
namespace { |
|
|
|
|
|
|
|
|
|
bool IsGroupSyntax(const FieldDescriptor* desc) { |
|
|
|
|
if (FileDescriptorLegacy(desc->file()).syntax() == |
|
|
|
|
FileDescriptorLegacy::SYNTAX_EDITIONS) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
return desc->type() == FieldDescriptor::TYPE_GROUP; |
|
|
|
|
return IsLegacyEdition(desc) && desc->type() == FieldDescriptor::TYPE_GROUP; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename OptionsT> |
|
|
|
@ -3125,6 +3131,13 @@ bool FormatLineOptions(int depth, const Message& options, |
|
|
|
|
return !all_options.empty(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static std::string GetLegacySyntaxName(const FileDescriptor* file) { |
|
|
|
|
if (file->edition() == Edition::EDITION_PROTO3) { |
|
|
|
|
return "proto3"; |
|
|
|
|
} |
|
|
|
|
return "proto2"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SourceLocationCommentPrinter { |
|
|
|
|
public: |
|
|
|
@ -3202,13 +3215,11 @@ std::string FileDescriptor::DebugStringWithOptions( |
|
|
|
|
SourceLocationCommentPrinter syntax_comment(this, path, "", |
|
|
|
|
debug_string_options); |
|
|
|
|
syntax_comment.AddPreComment(&contents); |
|
|
|
|
if (FileDescriptorLegacy(this).syntax() == |
|
|
|
|
FileDescriptorLegacy::SYNTAX_EDITIONS) { |
|
|
|
|
absl::SubstituteAndAppend(&contents, "edition = \"$0\";\n\n", edition()); |
|
|
|
|
} else { |
|
|
|
|
if (IsLegacyEdition(this)) { |
|
|
|
|
absl::SubstituteAndAppend(&contents, "syntax = \"$0\";\n\n", |
|
|
|
|
FileDescriptorLegacy::SyntaxName( |
|
|
|
|
FileDescriptorLegacy(this).syntax())); |
|
|
|
|
GetLegacySyntaxName(this)); |
|
|
|
|
} else { |
|
|
|
|
absl::SubstituteAndAppend(&contents, "edition = \"$0\";\n\n", edition()); |
|
|
|
|
} |
|
|
|
|
syntax_comment.AddPostComment(&contents); |
|
|
|
|
} |
|
|
|
@ -3481,13 +3492,11 @@ void FieldDescriptor::DebugString( |
|
|
|
|
|
|
|
|
|
// Label is omitted for maps, oneof, and plain proto3 fields.
|
|
|
|
|
if (is_map() || real_containing_oneof() || |
|
|
|
|
(is_optional() && !FieldDescriptorLegacy(this).has_optional_keyword())) { |
|
|
|
|
(is_optional() && !has_optional_keyword())) { |
|
|
|
|
label.clear(); |
|
|
|
|
} |
|
|
|
|
// Label is omitted for optional and required fields under editions.
|
|
|
|
|
if ((is_optional() || is_required()) && |
|
|
|
|
FileDescriptorLegacy(file()).syntax() == |
|
|
|
|
FileDescriptorLegacy::SYNTAX_EDITIONS) { |
|
|
|
|
if ((is_optional() || is_required()) && !IsLegacyEdition(this)) { |
|
|
|
|
label.clear(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -4261,7 +4270,6 @@ class DescriptorBuilder { |
|
|
|
|
void CheckFieldJsonNameUniqueness(const std::string& message_name, |
|
|
|
|
const DescriptorProto& message, |
|
|
|
|
const Descriptor* descriptor, |
|
|
|
|
FileDescriptorLegacy::Syntax syntax, |
|
|
|
|
bool use_custom_names); |
|
|
|
|
void CheckEnumValueUniqueness(const EnumDescriptorProto& proto, |
|
|
|
|
const EnumDescriptor* result); |
|
|
|
@ -5061,7 +5069,7 @@ FileDescriptor* DescriptorPool::NewPlaceholderFileWithMutexHeld( |
|
|
|
|
placeholder->tables_ = &FileDescriptorTables::GetEmptyInstance(); |
|
|
|
|
placeholder->source_code_info_ = &SourceCodeInfo::default_instance(); |
|
|
|
|
placeholder->is_placeholder_ = true; |
|
|
|
|
placeholder->syntax_ = FileDescriptorLegacy::SYNTAX_UNKNOWN; |
|
|
|
|
placeholder->syntax_ = FileDescriptor::SYNTAX_UNKNOWN; |
|
|
|
|
placeholder->finished_building_ = true; |
|
|
|
|
// All other fields are zero or nullptr.
|
|
|
|
|
|
|
|
|
@ -5283,14 +5291,12 @@ typename DescriptorT::OptionsType* DescriptorBuilder::AllocateOptionsImpl( |
|
|
|
|
|
|
|
|
|
template <class ProtoT, class OptionsT> |
|
|
|
|
static void InferLegacyProtoFeatures(const ProtoT& proto, |
|
|
|
|
const OptionsT& options, |
|
|
|
|
FileDescriptorLegacy::Syntax syntax, |
|
|
|
|
const OptionsT& options, Edition edition, |
|
|
|
|
FeatureSet& features) {} |
|
|
|
|
|
|
|
|
|
static void InferLegacyProtoFeatures(const FieldDescriptorProto& proto, |
|
|
|
|
const FieldOptions& options, |
|
|
|
|
FileDescriptorLegacy::Syntax syntax, |
|
|
|
|
FeatureSet& features) { |
|
|
|
|
Edition edition, FeatureSet& features) { |
|
|
|
|
if (proto.label() == FieldDescriptorProto::LABEL_REQUIRED) { |
|
|
|
|
features.set_field_presence(FeatureSet::LEGACY_REQUIRED); |
|
|
|
|
} |
|
|
|
@ -5300,25 +5306,13 @@ static void InferLegacyProtoFeatures(const FieldDescriptorProto& proto, |
|
|
|
|
if (options.packed()) { |
|
|
|
|
features.set_repeated_field_encoding(FeatureSet::PACKED); |
|
|
|
|
} |
|
|
|
|
if (syntax == FileDescriptorLegacy::SYNTAX_PROTO3) { |
|
|
|
|
if (edition == Edition::EDITION_PROTO3) { |
|
|
|
|
if (options.has_packed() && !options.packed()) { |
|
|
|
|
features.set_repeated_field_encoding(FeatureSet::EXPANDED); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <class DescriptorT> |
|
|
|
|
FileDescriptorLegacy::Syntax GetDescriptorSyntax( |
|
|
|
|
const DescriptorT* descriptor) { |
|
|
|
|
return FileDescriptorLegacy(descriptor->file()).syntax(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <> |
|
|
|
|
FileDescriptorLegacy::Syntax GetDescriptorSyntax( |
|
|
|
|
const FileDescriptor* descriptor) { |
|
|
|
|
return FileDescriptorLegacy(descriptor).syntax(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <class DescriptorT> |
|
|
|
|
void DescriptorBuilder::ResolveFeaturesImpl( |
|
|
|
|
const typename DescriptorT::Proto& proto, DescriptorT* descriptor, |
|
|
|
@ -5342,13 +5336,12 @@ void DescriptorBuilder::ResolveFeaturesImpl( |
|
|
|
|
FeatureSet base_features = *descriptor->proto_features_; |
|
|
|
|
|
|
|
|
|
// Handle feature inference from proto2/proto3.
|
|
|
|
|
if (GetDescriptorSyntax(descriptor) != |
|
|
|
|
FileDescriptorLegacy::SYNTAX_EDITIONS) { |
|
|
|
|
if (IsLegacyEdition(descriptor)) { |
|
|
|
|
if (descriptor->proto_features_ != &FeatureSet::default_instance()) { |
|
|
|
|
AddError(descriptor->name(), proto, error_location, |
|
|
|
|
"Features are only valid under editions."); |
|
|
|
|
} |
|
|
|
|
InferLegacyProtoFeatures(proto, *options, GetDescriptorSyntax(descriptor), |
|
|
|
|
InferLegacyProtoFeatures(proto, *options, GetDescriptorEdition(descriptor), |
|
|
|
|
base_features); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -5464,13 +5457,9 @@ PROTOBUF_NOINLINE static bool ExistingFileMatchesProto( |
|
|
|
|
const FileDescriptor* existing_file, const FileDescriptorProto& proto) { |
|
|
|
|
FileDescriptorProto existing_proto; |
|
|
|
|
existing_file->CopyTo(&existing_proto); |
|
|
|
|
// TODO: Remove it when CopyTo supports copying syntax params when
|
|
|
|
|
// syntax="proto2".
|
|
|
|
|
if (FileDescriptorLegacy(existing_file).syntax() == |
|
|
|
|
FileDescriptorLegacy::Syntax::SYNTAX_PROTO2 && |
|
|
|
|
if (existing_file->edition() == Edition::EDITION_PROTO2 && |
|
|
|
|
proto.has_syntax()) { |
|
|
|
|
existing_proto.set_syntax(FileDescriptorLegacy::SyntaxName( |
|
|
|
|
FileDescriptorLegacy(existing_file).syntax())); |
|
|
|
|
existing_proto.set_syntax("proto2"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return existing_proto.SerializeAsString() == proto.SerializeAsString(); |
|
|
|
@ -5692,16 +5681,16 @@ FileDescriptor* DescriptorBuilder::BuildFileImpl( |
|
|
|
|
// TODO: Report error when the syntax is empty after all the protos
|
|
|
|
|
// have added the syntax statement.
|
|
|
|
|
if (proto.syntax().empty() || proto.syntax() == "proto2") { |
|
|
|
|
file_->syntax_ = FileDescriptorLegacy::SYNTAX_PROTO2; |
|
|
|
|
file_->syntax_ = FileDescriptor::SYNTAX_PROTO2; |
|
|
|
|
file_->edition_ = Edition::EDITION_PROTO2; |
|
|
|
|
} else if (proto.syntax() == "proto3") { |
|
|
|
|
file_->syntax_ = FileDescriptorLegacy::SYNTAX_PROTO3; |
|
|
|
|
file_->syntax_ = FileDescriptor::SYNTAX_PROTO3; |
|
|
|
|
file_->edition_ = Edition::EDITION_PROTO3; |
|
|
|
|
} else if (proto.syntax() == "editions") { |
|
|
|
|
file_->syntax_ = FileDescriptorLegacy::SYNTAX_EDITIONS; |
|
|
|
|
file_->syntax_ = FileDescriptor::SYNTAX_EDITIONS; |
|
|
|
|
file_->edition_ = proto.edition(); |
|
|
|
|
} else { |
|
|
|
|
file_->syntax_ = FileDescriptorLegacy::SYNTAX_UNKNOWN; |
|
|
|
|
file_->syntax_ = FileDescriptor::SYNTAX_UNKNOWN; |
|
|
|
|
file_->edition_ = Edition::EDITION_UNKNOWN; |
|
|
|
|
AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER, [&] { |
|
|
|
|
return absl::StrCat("Unrecognized syntax: ", proto.syntax()); |
|
|
|
@ -6215,21 +6204,19 @@ void DescriptorBuilder::BuildMessage(const DescriptorProto& proto, |
|
|
|
|
|
|
|
|
|
void DescriptorBuilder::CheckFieldJsonNameUniqueness( |
|
|
|
|
const DescriptorProto& proto, const Descriptor* result) { |
|
|
|
|
FileDescriptorLegacy::Syntax syntax = |
|
|
|
|
FileDescriptorLegacy(result->file()).syntax(); |
|
|
|
|
std::string message_name = result->full_name(); |
|
|
|
|
if (pool_->deprecated_legacy_json_field_conflicts_ || |
|
|
|
|
IsLegacyJsonFieldConflictEnabled(result->options())) { |
|
|
|
|
if (syntax == FileDescriptorLegacy::Syntax::SYNTAX_PROTO3) { |
|
|
|
|
if (result->file()->edition() == Edition::EDITION_PROTO3) { |
|
|
|
|
// Only check default JSON names for conflicts in proto3. This is legacy
|
|
|
|
|
// behavior that will be removed in a later version.
|
|
|
|
|
CheckFieldJsonNameUniqueness(message_name, proto, result, syntax, false); |
|
|
|
|
CheckFieldJsonNameUniqueness(message_name, proto, result, false); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Check both with and without taking json_name into consideration. This is
|
|
|
|
|
// needed for field masks, which don't use json_name.
|
|
|
|
|
CheckFieldJsonNameUniqueness(message_name, proto, result, syntax, false); |
|
|
|
|
CheckFieldJsonNameUniqueness(message_name, proto, result, syntax, true); |
|
|
|
|
CheckFieldJsonNameUniqueness(message_name, proto, result, false); |
|
|
|
|
CheckFieldJsonNameUniqueness(message_name, proto, result, true); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -6260,8 +6247,7 @@ bool JsonNameLooksLikeExtension(std::string name) { |
|
|
|
|
|
|
|
|
|
void DescriptorBuilder::CheckFieldJsonNameUniqueness( |
|
|
|
|
const std::string& message_name, const DescriptorProto& message, |
|
|
|
|
const Descriptor* descriptor, FileDescriptorLegacy::Syntax syntax, |
|
|
|
|
bool use_custom_names) { |
|
|
|
|
const Descriptor* descriptor, bool use_custom_names) { |
|
|
|
|
absl::flat_hash_map<std::string, JsonNameDetails> name_to_field; |
|
|
|
|
for (const FieldDescriptorProto& field : message.field()) { |
|
|
|
|
JsonNameDetails details = GetJsonNameDetails(&field, use_custom_names); |
|
|
|
@ -6345,9 +6331,7 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto, |
|
|
|
|
result->is_oneof_ = false; |
|
|
|
|
result->proto3_optional_ = proto.proto3_optional(); |
|
|
|
|
|
|
|
|
|
if (proto.proto3_optional() && |
|
|
|
|
FileDescriptorLegacy(file_).syntax() != |
|
|
|
|
FileDescriptorLegacy::Syntax::SYNTAX_PROTO3) { |
|
|
|
|
if (proto.proto3_optional() && file_->edition() != Edition::EDITION_PROTO3) { |
|
|
|
|
AddError(result->full_name(), proto, DescriptorPool::ErrorCollector::TYPE, |
|
|
|
|
[&] { |
|
|
|
|
return absl::StrCat( |
|
|
|
@ -6747,8 +6731,7 @@ void DescriptorBuilder::CheckEnumValueUniqueness( |
|
|
|
|
// compatibility we issue only a warning for proto2.
|
|
|
|
|
if ((pool_->deprecated_legacy_json_field_conflicts_ || |
|
|
|
|
IsLegacyJsonFieldConflictEnabled(result->options())) && |
|
|
|
|
FileDescriptorLegacy(result->file()).syntax() == |
|
|
|
|
FileDescriptorLegacy::Syntax::SYNTAX_PROTO2) { |
|
|
|
|
result->file()->edition() == Edition::EDITION_PROTO2) { |
|
|
|
|
AddWarning(value->full_name(), proto.value(i), |
|
|
|
|
DescriptorPool::ErrorCollector::NAME, make_error); |
|
|
|
|
continue; |
|
|
|
@ -7095,7 +7078,7 @@ void DescriptorBuilder::CrossLinkMessage(Descriptor* message, |
|
|
|
|
const FieldDescriptor* field = message->field(i); |
|
|
|
|
if (field->proto3_optional_) { |
|
|
|
|
if (!field->containing_oneof() || |
|
|
|
|
!OneofDescriptorLegacy(field->containing_oneof()).is_synthetic()) { |
|
|
|
|
!field->containing_oneof()->is_synthetic()) { |
|
|
|
|
AddError(message->full_name(), proto.field(i), |
|
|
|
|
DescriptorPool::ErrorCollector::OTHER, |
|
|
|
|
"Fields with proto3_optional set must be " |
|
|
|
@ -7107,8 +7090,7 @@ void DescriptorBuilder::CrossLinkMessage(Descriptor* message, |
|
|
|
|
// Synthetic oneofs must be last.
|
|
|
|
|
int first_synthetic = -1; |
|
|
|
|
for (int i = 0; i < message->oneof_decl_count(); i++) { |
|
|
|
|
const OneofDescriptor* oneof = message->oneof_decl(i); |
|
|
|
|
if (OneofDescriptorLegacy(oneof).is_synthetic()) { |
|
|
|
|
if (message->oneof_decl(i)->is_synthetic()) { |
|
|
|
|
if (first_synthetic == -1) { |
|
|
|
|
first_synthetic = i; |
|
|
|
|
} |
|
|
|
@ -7672,8 +7654,7 @@ void DescriptorBuilder::ValidateOptions(const FileDescriptor* file, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (FileDescriptorLegacy(file).syntax() == |
|
|
|
|
FileDescriptorLegacy::Syntax::SYNTAX_PROTO3) { |
|
|
|
|
if (file->edition() == Edition::EDITION_PROTO3) { |
|
|
|
|
ValidateProto3(file, proto); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -7915,8 +7896,7 @@ static bool IsStringMapType(const FieldDescriptor& field) { |
|
|
|
|
void DescriptorBuilder::ValidateFileFeatures(const FileDescriptor* file, |
|
|
|
|
const FileDescriptorProto& proto) { |
|
|
|
|
// Rely on our legacy validation for proto2/proto3 files.
|
|
|
|
|
if (FileDescriptorLegacy(file).syntax() != |
|
|
|
|
FileDescriptorLegacy::SYNTAX_EDITIONS) { |
|
|
|
|
if (IsLegacyEdition(file)) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -7935,8 +7915,7 @@ void DescriptorBuilder::ValidateFileFeatures(const FileDescriptor* file, |
|
|
|
|
void DescriptorBuilder::ValidateFieldFeatures( |
|
|
|
|
const FieldDescriptor* field, const FieldDescriptorProto& proto) { |
|
|
|
|
// Rely on our legacy validation for proto2/proto3 files.
|
|
|
|
|
if (FileDescriptorLegacy(field->file()).syntax() != |
|
|
|
|
FileDescriptorLegacy::SYNTAX_EDITIONS) { |
|
|
|
|
if (field->file()->edition() < Edition::EDITION_2023) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|