diff --git a/src/google/protobuf/compiler/objectivec/message.cc b/src/google/protobuf/compiler/objectivec/message.cc index 7330ef08a9..4f65711b66 100644 --- a/src/google/protobuf/compiler/objectivec/message.cc +++ b/src/google/protobuf/compiler/objectivec/message.cc @@ -46,6 +46,7 @@ #include "google/protobuf/compiler/objectivec/names.h" #include "google/protobuf/compiler/objectivec/oneof.h" #include "google/protobuf/compiler/objectivec/text_format_decode_data.h" +#include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/io/printer.h" @@ -153,6 +154,39 @@ struct ExtensionRangeOrdering { } }; +// This is a reduced case of Descriptor::ExtensionRange with just start and end. +struct SimpleExtensionRange { + SimpleExtensionRange(int start, int end) : start(start), end(end){}; + int start; // inclusive + int end; // exclusive + + // Descriptors expose extension ranges in the order they were defined in the + // file, but this reorders and merges the ranges that are contiguous (i.e. - + // [(21,30),(10,20)] -> [(10,30)]) + static std::vector Normalize( + const Descriptor* descriptor) { + std::vector sorted_extensions; + sorted_extensions.reserve(descriptor->extension_range_count()); + for (int i = 0; i < descriptor->extension_range_count(); ++i) { + sorted_extensions.push_back(descriptor->extension_range(i)); + } + + std::sort(sorted_extensions.begin(), sorted_extensions.end(), + ExtensionRangeOrdering()); + + std::vector result; + result.reserve(sorted_extensions.size()); + for (const auto ext : sorted_extensions) { + if (!result.empty() && result.back().end == ext->start) { + result.back().end = ext->end; + } else { + result.emplace_back(ext->start, ext->end); + } + } + return result; + } +}; + // Sort the fields of the given Descriptor by number into a new[]'d array // and return it. const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { @@ -387,14 +421,8 @@ void MessageGenerator::GenerateSource(io::Printer* printer) const { std::unique_ptr size_order_fields( SortFieldsByStorageSize(descriptor_)); - std::vector sorted_extensions; - sorted_extensions.reserve(descriptor_->extension_range_count()); - for (int i = 0; i < descriptor_->extension_range_count(); ++i) { - sorted_extensions.push_back(descriptor_->extension_range(i)); - } - - std::sort(sorted_extensions.begin(), sorted_extensions.end(), - ExtensionRangeOrdering()); + std::vector sorted_extensions( + SimpleExtensionRange::Normalize(descriptor_)); printer->Print( // clang-format off @@ -528,10 +556,10 @@ void MessageGenerator::GenerateSource(io::Printer* printer) const { } if (!sorted_extensions.empty()) { printer->Print(" static const GPBExtensionRange ranges[] = {\n"); - for (int i = 0; i < sorted_extensions.size(); i++) { + for (const auto& extension_range : sorted_extensions) { printer->Print(" { .start = $start$, .end = $end$ },\n", "start", - absl::StrCat(sorted_extensions[i]->start), "end", - absl::StrCat(sorted_extensions[i]->end)); + absl::StrCat(extension_range.start), "end", + absl::StrCat(extension_range.end)); } // clang-format off printer->Print(