diff options
author | nechda <[email protected]> | 2024-08-29 23:50:27 +0300 |
---|---|---|
committer | nechda <[email protected]> | 2024-08-30 00:05:25 +0300 |
commit | e10d6638f07a82edae3ea8197b9f5c0affcc07ea (patch) | |
tree | 571c38cec05813766a1ad290c9d51ce7ace52919 /contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc | |
parent | e79b38f2bbbf78d295d1901d2a79f898022d5224 (diff) |
Update cpp-protobuf to 22.5
Привет!\
Этот PR переключат cpp & python библиотеки protobuf на версию 22.5
Если у вас возникли проблемы после влития этого PR:
1. Если начали падать канон тесты, то проведите их переканонизацию
2. Прочитайте <https://wiki.yandex-team.ru/users/nechda/obnovlenie-cpp-protobuf-22.5/> страничку с основными изменениями
3. Если страничка в вики не помогла, то пишите в [DEVTOOLSSUPPORT](https://st.yandex-team.ru/DEVTOOLSSUPPORT)
7fecade616c20a841b9e9af7b7998bdfc8d2807d
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc')
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc | 575 |
1 files changed, 361 insertions, 214 deletions
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc b/contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc index 3de6dc2f6d6..4568848cd11 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc @@ -32,11 +32,15 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/command_line_interface.h> +#include "google/protobuf/compiler/command_line_interface.h" -#include <google/protobuf/stubs/platform_macros.h> +#include "y_absl/container/btree_set.h" +#include "y_absl/container/flat_hash_map.h" + +#include "google/protobuf/stubs/platform_macros.h" #include <stdio.h> +#include <stdlib.h> #include <sys/types.h> #ifdef major #undef major @@ -58,6 +62,9 @@ #include <limits.h> // For PATH_MAX #include <memory> +#include <string> +#include <utility> +#include <vector> #if defined(__APPLE__) #include <mach-o/dyld.h> @@ -65,29 +72,32 @@ #include <sys/sysctl.h> #endif -#include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/logging.h> -#include <google/protobuf/compiler/subprocess.h> -#include <google/protobuf/compiler/plugin.pb.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/stringprintf.h> -#include <google/protobuf/stubs/substitute.h> -#include <google/protobuf/compiler/code_generator.h> -#include <google/protobuf/compiler/importer.h> -#include <google/protobuf/compiler/zip_writer.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/dynamic_message.h> -#include <google/protobuf/io/coded_stream.h> -#include <google/protobuf/io/io_win32.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream_impl.h> -#include <google/protobuf/text_format.h> -#include <google/protobuf/stubs/map_util.h> -#include <google/protobuf/stubs/stl_util.h> +#include "google/protobuf/stubs/common.h" +#include "y_absl/log/absl_check.h" +#include "y_absl/log/absl_log.h" +#include "google/protobuf/compiler/subprocess.h" +#include "google/protobuf/compiler/plugin.pb.h" +#include "y_absl/container/flat_hash_set.h" +#include "y_absl/strings/match.h" +#include "y_absl/strings/str_format.h" +#include "y_absl/strings/str_replace.h" +#include "y_absl/strings/str_split.h" +#include "y_absl/strings/string_view.h" +#include "y_absl/strings/substitute.h" +#include "google/protobuf/compiler/code_generator.h" +#include "google/protobuf/compiler/importer.h" +#include "google/protobuf/compiler/zip_writer.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/dynamic_message.h" +#include "google/protobuf/io/coded_stream.h" +#include "google/protobuf/io/io_win32.h" +#include "google/protobuf/io/printer.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include "google/protobuf/text_format.h" // Must be included last. -#include <google/protobuf/port_def.inc> +#include "google/protobuf/port_def.inc" namespace google { namespace protobuf { @@ -132,7 +142,7 @@ void SetFdToTextMode(int fd) { #ifdef _WIN32 if (setmode(fd, _O_TEXT) == -1) { // This should never happen, I think. - GOOGLE_LOG(WARNING) << "setmode(" << fd << ", _O_TEXT): " << strerror(errno); + Y_ABSL_LOG(WARNING) << "setmode(" << fd << ", _O_TEXT): " << strerror(errno); } #endif // (Text and binary are the same on non-Windows platforms.) @@ -142,7 +152,8 @@ void SetFdToBinaryMode(int fd) { #ifdef _WIN32 if (setmode(fd, _O_BINARY) == -1) { // This should never happen, I think. - GOOGLE_LOG(WARNING) << "setmode(" << fd << ", _O_BINARY): " << strerror(errno); + Y_ABSL_LOG(WARNING) << "setmode(" << fd + << ", _O_BINARY): " << strerror(errno); } #endif // (Text and binary are the same on non-Windows platforms.) @@ -174,7 +185,7 @@ bool TryCreateParentDirectory(const TProtoStringType& prefix, // Recursively create parent directories to the output file. // On Windows, both '/' and '\' are valid path separators. std::vector<TProtoStringType> parts = - Split(filename, "/\\", true); + y_absl::StrSplit(filename, y_absl::ByAnyChar("/\\"), y_absl::SkipEmpty()); TProtoStringType path_so_far = prefix; for (int i = 0; i < parts.size() - 1; i++) { path_so_far += parts[i]; @@ -227,9 +238,10 @@ bool GetProtocAbsolutePath(TProtoStringType* path) { // Whether a path is where google/protobuf/descriptor.proto and other well-known // type protos are installed. -bool IsInstalledProtoPath(const TProtoStringType& path) { +bool IsInstalledProtoPath(y_absl::string_view path) { // Checking the descriptor.proto file should be good enough. - TProtoStringType file_path = path + "/google/protobuf/descriptor.proto"; + TProtoStringType file_path = + y_absl::StrCat(path, "/google/protobuf/descriptor.proto"); return access(file_path.c_str(), F_OK) != -1; } @@ -240,25 +252,26 @@ void AddDefaultProtoPaths( // TODO(xiaofeng): The code currently only checks relative paths of where // the protoc binary is installed. We probably should make it handle more // cases than that. - TProtoStringType path; - if (!GetProtocAbsolutePath(&path)) { + TProtoStringType path_str; + if (!GetProtocAbsolutePath(&path_str)) { return; } + y_absl::string_view path(path_str); // Strip the binary name. size_t pos = path.find_last_of("/\\"); - if (pos == TProtoStringType::npos || pos == 0) { + if (pos == path.npos || pos == 0) { return; } path = path.substr(0, pos); // Check the binary's directory. if (IsInstalledProtoPath(path)) { - paths->push_back(std::pair<TProtoStringType, TProtoStringType>("", path)); + paths->emplace_back("", path); return; } // Check if there is an include subdirectory. - if (IsInstalledProtoPath(path + "/include")) { - paths->push_back( - std::pair<TProtoStringType, TProtoStringType>("", path + "/include")); + TProtoStringType include_path = y_absl::StrCat(path, "/include"); + if (IsInstalledProtoPath(include_path)) { + paths->emplace_back("", std::move(include_path)); return; } // Check if the upper level directory has an "include" subdirectory. @@ -267,18 +280,19 @@ void AddDefaultProtoPaths( return; } path = path.substr(0, pos); - if (IsInstalledProtoPath(path + "/include")) { - paths->push_back( - std::pair<TProtoStringType, TProtoStringType>("", path + "/include")); + include_path = y_absl::StrCat(path, "/include"); + if (IsInstalledProtoPath(include_path)) { + paths->emplace_back("", std::move(include_path)); return; } } -TProtoStringType PluginName(const TProtoStringType& plugin_prefix, - const TProtoStringType& directive) { +TProtoStringType PluginName(y_absl::string_view plugin_prefix, + y_absl::string_view directive) { // Assuming the directive starts with "--" and ends with "_out" or "_opt", // strip the "--" and "_out/_opt" and add the plugin prefix. - return plugin_prefix + "gen-" + directive.substr(2, directive.size() - 6); + return y_absl::StrCat(plugin_prefix, "gen-", + directive.substr(2, directive.size() - 6)); } } // namespace @@ -297,37 +311,37 @@ class CommandLineInterface::ErrorPrinter ~ErrorPrinter() override {} // implements MultiFileErrorCollector ------------------------------ - void AddError(const TProtoStringType& filename, int line, int column, - const TProtoStringType& message) override { + void RecordError(y_absl::string_view filename, int line, int column, + y_absl::string_view message) override { found_errors_ = true; AddErrorOrWarning(filename, line, column, message, "error", std::cerr); } - void AddWarning(const TProtoStringType& filename, int line, int column, - const TProtoStringType& message) override { + void RecordWarning(y_absl::string_view filename, int line, int column, + y_absl::string_view message) override { found_warnings_ = true; AddErrorOrWarning(filename, line, column, message, "warning", std::clog); } // implements io::ErrorCollector ----------------------------------- - void AddError(int line, int column, const TProtoStringType& message) override { - AddError("input", line, column, message); + void RecordError(int line, int column, y_absl::string_view message) override { + RecordError("input", line, column, message); } - void AddWarning(int line, int column, const TProtoStringType& message) override { + void RecordWarning(int line, int column, y_absl::string_view message) override { AddErrorOrWarning("input", line, column, message, "warning", std::clog); } // implements DescriptorPool::ErrorCollector------------------------- - void AddError(const TProtoStringType& filename, const TProtoStringType& element_name, - const Message* descriptor, ErrorLocation location, - const TProtoStringType& message) override { + void RecordError(y_absl::string_view filename, y_absl::string_view element_name, + const Message* descriptor, ErrorLocation location, + y_absl::string_view message) override { AddErrorOrWarning(filename, -1, -1, message, "error", std::cerr); } - void AddWarning(const TProtoStringType& filename, const TProtoStringType& element_name, - const Message* descriptor, ErrorLocation location, - const TProtoStringType& message) override { + void RecordWarning(y_absl::string_view filename, y_absl::string_view element_name, + const Message* descriptor, ErrorLocation location, + y_absl::string_view message) override { AddErrorOrWarning(filename, -1, -1, message, "warning", std::clog); } @@ -336,12 +350,15 @@ class CommandLineInterface::ErrorPrinter bool FoundWarnings() const { return found_warnings_; } private: - void AddErrorOrWarning(const TProtoStringType& filename, int line, int column, - const TProtoStringType& message, const TProtoStringType& type, + void AddErrorOrWarning(y_absl::string_view filename, int line, int column, + y_absl::string_view message, y_absl::string_view type, std::ostream& out) { - // Print full path when running under MSVS TProtoStringType dfile; - if (format_ == CommandLineInterface::ERROR_FORMAT_MSVS && + if ( +#ifndef PROTOBUF_OPENSOURCE + // Print full path when running under MSVS + format_ == CommandLineInterface::ERROR_FORMAT_MSVS && +#endif // !PROTOBUF_OPENSOURCE tree_ != nullptr && tree_->VirtualFileToDiskFile(filename, &dfile)) { out << dfile; } else { @@ -398,7 +415,6 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext { // Get name of all output files. void GetOutputFilenames(std::vector<TProtoStringType>* output_filenames); - // implements GeneratorContext -------------------------------------- io::ZeroCopyOutputStream* Open(const TProtoStringType& filename) override; io::ZeroCopyOutputStream* OpenForAppend(const TProtoStringType& filename) override; @@ -417,7 +433,7 @@ class CommandLineInterface::GeneratorContextImpl : public GeneratorContext { // The files_ field maps from path keys to file content values. It's a map // instead of an unordered_map so that files are written in order (good when // writing zips). - std::map<TProtoStringType, TProtoStringType> files_; + y_absl::btree_map<TProtoStringType, TProtoStringType> files_; const std::vector<const FileDescriptor*>& parsed_files_; bool had_error_; }; @@ -708,7 +724,7 @@ void CommandLineInterface::MemoryOutputStream::InsertShiftedInfo( void CommandLineInterface::MemoryOutputStream::UpdateMetadata( const TProtoStringType& insertion_content, size_t insertion_offset, size_t insertion_length, size_t indent_length) { - auto it = directory_->files_.find(filename_ + ".pb.meta"); + auto it = directory_->files_.find(y_absl::StrCat(filename_, ".pb.meta")); if (it == directory_->files_.end() && info_to_insert_.annotation().empty()) { // No metadata was recorded for this file. return; @@ -738,7 +754,8 @@ void CommandLineInterface::MemoryOutputStream::UpdateMetadata( } else { // Create a new file to store the new metadata in info_to_insert_. encoded_data = - &directory_->files_.insert({filename_ + ".pb.meta", ""}).first->second; + &directory_->files_.try_emplace(y_absl::StrCat(filename_, ".pb.meta"), "") + .first->second; } GeneratedCodeInfo new_metadata; bool crossed_offset = false; @@ -795,96 +812,95 @@ CommandLineInterface::MemoryOutputStream::~MemoryOutputStream() { } it->second.swap(data_); - } else { - // This was an OpenForInsert(). + return; + } + // This was an OpenForInsert(). - // If the data doesn't end with a clean line break, add one. - if (!data_.empty() && data_[data_.size() - 1] != '\n') { - data_.push_back('\n'); - } + // If the data doesn't end with a clean line break, add one. + if (!data_.empty() && data_[data_.size() - 1] != '\n') { + data_.push_back('\n'); + } - // Find the file we are going to insert into. - if (!already_present) { - std::cerr << filename_ - << ": Tried to insert into file that doesn't exist." - << std::endl; - directory_->had_error_ = true; - return; - } - TProtoStringType* target = &it->second; + // Find the file we are going to insert into. + if (!already_present) { + std::cerr << filename_ << ": Tried to insert into file that doesn't exist." + << std::endl; + directory_->had_error_ = true; + return; + } + TProtoStringType* target = &it->second; - // Find the insertion point. - TProtoStringType magic_string = - strings::Substitute("@@protoc_insertion_point($0)", insertion_point_); - TProtoStringType::size_type pos = target->find(magic_string); + // Find the insertion point. + TProtoStringType magic_string = + y_absl::Substitute("@@protoc_insertion_point($0)", insertion_point_); + TProtoStringType::size_type pos = target->find(magic_string); - if (pos == TProtoStringType::npos) { - std::cerr << filename_ << ": insertion point \"" << insertion_point_ - << "\" not found." << std::endl; - directory_->had_error_ = true; - return; - } + if (pos == TProtoStringType::npos) { + std::cerr << filename_ << ": insertion point \"" << insertion_point_ + << "\" not found." << std::endl; + directory_->had_error_ = true; + return; + } - if ((pos > 3) && (target->substr(pos - 3, 2) == "/*")) { - // Support for inline "/* @@protoc_insertion_point() */" - pos = pos - 3; + if ((pos > 3) && (target->substr(pos - 3, 2) == "/*")) { + // Support for inline "/* @@protoc_insertion_point() */" + pos = pos - 3; + } else { + // Seek backwards to the beginning of the line, which is where we will + // insert the data. Note that this has the effect of pushing the + // insertion point down, so the data is inserted before it. This is + // intentional because it means that multiple insertions at the same point + // will end up in the expected order in the final output. + pos = target->find_last_of('\n', pos); + if (pos == TProtoStringType::npos) { + // Insertion point is on the first line. + pos = 0; } else { - // Seek backwards to the beginning of the line, which is where we will - // insert the data. Note that this has the effect of pushing the - // insertion point down, so the data is inserted before it. This is - // intentional because it means that multiple insertions at the same point - // will end up in the expected order in the final output. - pos = target->find_last_of('\n', pos); - if (pos == TProtoStringType::npos) { - // Insertion point is on the first line. - pos = 0; - } else { - // Advance to character after '\n'. - ++pos; - } + // Advance to character after '\n'. + ++pos; } + } - // Extract indent. - TProtoStringType indent_(*target, pos, - target->find_first_not_of(" \t", pos) - pos); + // Extract indent. + TProtoStringType indent_(*target, pos, + target->find_first_not_of(" \t", pos) - pos); - if (indent_.empty()) { - // No indent. This makes things easier. - target->insert(pos, data_); - UpdateMetadata(data_, pos, data_.size(), 0); - } else { - // Calculate how much space we need. - int indent_size = 0; - for (int i = 0; i < data_.size(); i++) { - if (data_[i] == '\n') indent_size += indent_.size(); - } + if (indent_.empty()) { + // No indent. This makes things easier. + target->insert(pos, data_); + UpdateMetadata(data_, pos, data_.size(), 0); + return; + } + // Calculate how much space we need. + int indent_size = 0; + for (int i = 0; i < data_.size(); i++) { + if (data_[i] == '\n') indent_size += indent_.size(); + } - // Make a hole for it. - target->insert(pos, data_.size() + indent_size, '\0'); - - // Now copy in the data. - TProtoStringType::size_type data_pos = 0; - char* target_ptr = ::google::protobuf::string_as_array(target) + pos; - while (data_pos < data_.size()) { - // Copy indent. - memcpy(target_ptr, indent_.data(), indent_.size()); - target_ptr += indent_.size(); - - // Copy line from data_. - // We already guaranteed that data_ ends with a newline (above), so this - // search can't fail. - TProtoStringType::size_type line_length = - data_.find_first_of('\n', data_pos) + 1 - data_pos; - memcpy(target_ptr, data_.data() + data_pos, line_length); - target_ptr += line_length; - data_pos += line_length; - } - UpdateMetadata(data_, pos, data_.size() + indent_size, indent_.size()); + // Make a hole for it. + target->insert(pos, data_.size() + indent_size, '\0'); - GOOGLE_CHECK_EQ(target_ptr, - ::google::protobuf::string_as_array(target) + pos + data_.size() + indent_size); - } + // Now copy in the data. + TProtoStringType::size_type data_pos = 0; + char* target_ptr = &(*target)[pos]; + while (data_pos < data_.size()) { + // Copy indent. + memcpy(target_ptr, indent_.data(), indent_.size()); + target_ptr += indent_.size(); + + // Copy line from data_. + // We already guaranteed that data_ ends with a newline (above), so this + // search can't fail. + TProtoStringType::size_type line_length = + data_.find_first_of('\n', data_pos) + 1 - data_pos; + memcpy(target_ptr, data_.data() + data_pos, line_length); + target_ptr += line_length; + data_pos += line_length; } + + Y_ABSL_CHECK_EQ(target_ptr, &(*target)[pos] + data_.size() + indent_size); + + UpdateMetadata(data_, pos, data_.size() + indent_size, indent_.size()); } // =================================================================== @@ -954,6 +970,77 @@ bool ContainsProto3Optional(const FileDescriptor* file) { return false; } +template <typename Visitor> +struct VisitImpl { + Visitor visitor; + void Visit(const FieldDescriptor* descriptor) { visitor(descriptor); } + + void Visit(const EnumDescriptor* descriptor) { visitor(descriptor); } + + void Visit(const Descriptor* descriptor) { + visitor(descriptor); + + for (int i = 0; i < descriptor->enum_type_count(); i++) { + Visit(descriptor->enum_type(i)); + } + + for (int i = 0; i < descriptor->field_count(); i++) { + Visit(descriptor->field(i)); + } + + for (int i = 0; i < descriptor->nested_type_count(); i++) { + Visit(descriptor->nested_type(i)); + } + + for (int i = 0; i < descriptor->extension_count(); i++) { + Visit(descriptor->extension(i)); + } + } + + void Visit(const std::vector<const FileDescriptor*>& descriptors) { + for (auto* descriptor : descriptors) { + visitor(descriptor); + for (int i = 0; i < descriptor->message_type_count(); i++) { + Visit(descriptor->message_type(i)); + } + for (int i = 0; i < descriptor->enum_type_count(); i++) { + Visit(descriptor->enum_type(i)); + } + for (int i = 0; i < descriptor->extension_count(); i++) { + Visit(descriptor->extension(i)); + } + } + } +}; + +// Visit every node in the descriptors calling `visitor(node)`. +// The visitor does not need to handle all possible node types. Types that are +// not visitable via `visitor` will be ignored. +// Disclaimer: this is not fully implemented yet to visit _every_ node. +// VisitImpl might need to be updated where needs arise. +template <typename Visitor> +void VisitDescriptors(const std::vector<const FileDescriptor*>& descriptors, + Visitor visitor) { + // Provide a fallback to ignore all the nodes that are not interesting to the + // input visitor. + struct VisitorImpl : Visitor { + explicit VisitorImpl(Visitor visitor) : Visitor(visitor) {} + using Visitor::operator(); + // Honeypot to ignore all inputs that Visitor does not take. + void operator()(const void*) const {} + }; + + VisitImpl<VisitorImpl>{VisitorImpl(visitor)}.Visit(descriptors); +} + +bool HasReservedFieldNumber(const FieldDescriptor* field) { + if (field->number() >= FieldDescriptor::kFirstReservedNumber && + field->number() <= FieldDescriptor::kLastReservedNumber) { + return true; + } + return false; +} + } // namespace namespace { @@ -963,6 +1050,7 @@ PopulateSingleSimpleDescriptorDatabase(const TProtoStringType& descriptor_set_na int CommandLineInterface::Run(int argc, const char* const argv[]) { Clear(); + switch (ParseArguments(argc, argv)) { case PARSE_ARGUMENT_DONE_AND_EXIT: return 0; @@ -1046,6 +1134,38 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { return 1; } + bool validation_error = false; // Defer exiting so we log more warnings. + + VisitDescriptors(parsed_files, [&](const FieldDescriptor* field) { + if (HasReservedFieldNumber(field)) { + const char* error_link = nullptr; + validation_error = true; + TProtoStringType error; + if (field->number() >= FieldDescriptor::kFirstReservedNumber && + field->number() <= FieldDescriptor::kLastReservedNumber) { + error = y_absl::Substitute( + "Field numbers $0 through $1 are reserved " + "for the protocol buffer library implementation.", + FieldDescriptor::kFirstReservedNumber, + FieldDescriptor::kLastReservedNumber); + } else { + error = y_absl::Substitute( + "Field number $0 is reserved for specific purposes.", + field->number()); + } + if (error_link) { + y_absl::StrAppend(&error, "(See ", error_link, ")"); + } + static_cast<DescriptorPool::ErrorCollector*>(error_collector.get()) + ->RecordError(field->file()->name(), field->full_name(), nullptr, + DescriptorPool::ErrorCollector::NUMBER, error); + } + }); + + + if (validation_error) { + return 1; + } // We construct a separate GeneratorContext for each output location. Note // that two code generators may output to the same location, in which case @@ -1056,9 +1176,9 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { if (mode_ == MODE_COMPILE) { for (int i = 0; i < output_directives_.size(); i++) { TProtoStringType output_location = output_directives_[i].output_location; - if (!HasSuffixString(output_location, ".zip") && - !HasSuffixString(output_location, ".jar") && - !HasSuffixString(output_location, ".srcjar")) { + if (!y_absl::EndsWith(output_location, ".zip") && + !y_absl::EndsWith(output_location, ".jar") && + !y_absl::EndsWith(output_location, ".srcjar")) { AddTrailingSlash(&output_location); } @@ -1066,7 +1186,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { if (!generator) { // First time we've seen this output location. - generator.reset(new GeneratorContextImpl(parsed_files)); + generator = std::make_unique<GeneratorContextImpl>(parsed_files); } if (!GenerateOutput(parsed_files, output_directives_[i], @@ -1076,16 +1196,15 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { } } - // Write all output to disk. for (const auto& pair : output_directories) { const TProtoStringType& location = pair.first; GeneratorContextImpl* directory = pair.second.get(); - if (HasSuffixString(location, "/")) { + if (y_absl::EndsWith(location, "/")) { if (!directory->WriteAllToDisk(location)) { return 1; } } else { - if (HasSuffixString(location, ".jar")) { + if (y_absl::EndsWith(location, ".jar")) { directory->AddJarManifest(); } @@ -1096,7 +1215,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { } if (!dependency_out_name_.empty()) { - GOOGLE_DCHECK(disk_source_tree.get()); + Y_ABSL_DCHECK(disk_source_tree.get()); if (!GenerateDependencyManifestFile(parsed_files, output_directories, disk_source_tree.get())) { return 1; @@ -1116,7 +1235,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { FileDescriptorProto file; file.set_name("empty_message.proto"); file.add_message_type()->set_name("EmptyMessage"); - GOOGLE_CHECK(pool.BuildFile(file) != nullptr); + Y_ABSL_CHECK(pool.BuildFile(file) != nullptr); codec_type_ = "EmptyMessage"; if (!EncodeOrDecode(&pool)) { return 1; @@ -1144,14 +1263,14 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { } break; case PRINT_NONE: - GOOGLE_LOG(ERROR) << "If the code reaches here, it usually means a bug of " - "flag parsing in the CommandLineInterface."; + Y_ABSL_LOG(ERROR) + << "If the code reaches here, it usually means a bug of " + "flag parsing in the CommandLineInterface."; return 1; // Do not add a default case. } } - return 0; } @@ -1276,6 +1395,7 @@ bool CommandLineInterface::ParseInputFiles( } parsed_files->push_back(parsed_file); + // Enforce --disallow_services. if (disallow_services_ && parsed_file->service_count() > 0) { std::cerr << parsed_file->name() @@ -1295,9 +1415,9 @@ bool CommandLineInterface::ParseInputFiles( direct_dependencies_.end()) { indirect_imports = true; std::cerr << parsed_file->name() << ": " - << StringReplace(direct_dependencies_violation_msg_, "%s", - parsed_file->dependency(i)->name(), - true /* replace_all */) + << y_absl::StrReplaceAll( + direct_dependencies_violation_msg_, + {{"%s", parsed_file->dependency(i)->name()}}) << std::endl; } } @@ -1486,19 +1606,15 @@ CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments( // Make sure each plugin option has a matching plugin output. bool foundUnknownPluginOption = false; - for (std::map<TProtoStringType, TProtoStringType>::const_iterator i = - plugin_parameters_.begin(); - i != plugin_parameters_.end(); ++i) { - if (plugins_.find(i->first) != plugins_.end()) { + for (const auto& kv : plugin_parameters_) { + if (plugins_.find(kv.first) != plugins_.end()) { continue; } bool foundImplicitPlugin = false; - for (std::vector<OutputDirective>::const_iterator j = - output_directives_.begin(); - j != output_directives_.end(); ++j) { - if (j->generator == nullptr) { - TProtoStringType plugin_name = PluginName(plugin_prefix_, j->name); - if (plugin_name == i->first) { + for (const auto& d : output_directives_) { + if (d.generator == nullptr) { + TProtoStringType plugin_name = PluginName(plugin_prefix_, d.name); + if (plugin_name == kv.first) { foundImplicitPlugin = true; break; } @@ -1507,7 +1623,7 @@ CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments( if (!foundImplicitPlugin) { std::cerr << "Unknown flag: " // strip prefix + "gen-" and add back "_opt" - << "--" + i->first.substr(plugin_prefix_.size() + 4) + "_opt" + << "--" << kv.first.substr(plugin_prefix_.size() + 4) << "_opt" << std::endl; foundUnknownPluginOption = true; } @@ -1552,7 +1668,7 @@ CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments( input_files_.empty() && descriptor_set_in_names_.empty(); break; default: - GOOGLE_LOG(FATAL) << "Unexpected mode: " << mode_; + Y_ABSL_LOG(FATAL) << "Unexpected mode: " << mode_; } if (missing_proto_definitions) { std::cerr << "Missing input file." << std::endl; @@ -1686,8 +1802,7 @@ CommandLineInterface::InterpretArgument(const TProtoStringType& name, })) { case google::protobuf::io::win32::ExpandWildcardsResult::kSuccess: break; - case google::protobuf::io::win32::ExpandWildcardsResult:: - kErrorNoMatchingFile: + case google::protobuf::io::win32::ExpandWildcardsResult::kErrorNoMatchingFile: // Path does not exist, is not a file, or it's longer than MAX_PATH and // long path handling is disabled. std::cerr << "Invalid file name pattern or missing input file \"" @@ -1708,9 +1823,9 @@ CommandLineInterface::InterpretArgument(const TProtoStringType& name, // Java's -classpath (and some other languages) delimits path components // with colons. Let's accept that syntax too just to make things more // intuitive. - std::vector<TProtoStringType> parts = Split( - value, CommandLineInterface::kPathSeparator, - true); + std::vector<TProtoStringType> parts = y_absl::StrSplit( + value, y_absl::ByAnyChar(CommandLineInterface::kPathSeparator), + y_absl::SkipEmpty()); for (int i = 0; i < parts.size(); i++) { TProtoStringType virtual_path; @@ -1764,8 +1879,8 @@ CommandLineInterface::InterpretArgument(const TProtoStringType& name, direct_dependencies_explicitly_set_ = true; std::vector<TProtoStringType> direct = - Split(value, ":", true); - GOOGLE_DCHECK(direct_dependencies_.empty()); + y_absl::StrSplit(value, ":", y_absl::SkipEmpty()); + Y_ABSL_DCHECK(direct_dependencies_.empty()); direct_dependencies_.insert(direct.begin(), direct.end()); } else if (name == "--direct_dependencies_violation_msg") { @@ -1790,9 +1905,9 @@ CommandLineInterface::InterpretArgument(const TProtoStringType& name, return PARSE_ARGUMENT_FAIL; } - descriptor_set_in_names_ = Split( - value, CommandLineInterface::kPathSeparator, - true); + descriptor_set_in_names_ = y_absl::StrSplit( + value, y_absl::ByAnyChar(CommandLineInterface::kPathSeparator), + y_absl::SkipEmpty()); } else if (name == "-o" || name == "--descriptor_set_out") { if (!descriptor_set_out_name_.empty()) { @@ -1850,7 +1965,7 @@ CommandLineInterface::InterpretArgument(const TProtoStringType& name, if (!version_info_.empty()) { std::cout << version_info_ << std::endl; } - std::cout << "libprotoc " << internal::VersionString(PROTOBUF_VERSION) + std::cout << "libprotoc " << internal::ProtocVersionString(PROTOBUF_VERSION) << PROTOBUF_VERSION_SUFFIX << std::endl; return PARSE_ARGUMENT_DONE_AND_EXIT; // Exit without running compiler. @@ -1979,14 +2094,30 @@ CommandLineInterface::InterpretArgument(const TProtoStringType& name, } mode_ = MODE_PRINT; print_mode_ = PRINT_FREE_FIELDS; + } else if (name == "--enable_codegen_trace") { + // We use environment variables here so that subprocesses see this setting + // when we spawn them. + // + // Setting environment variables is more-or-less asking for a data race, + // because C got this wrong and did not mandate synchronization. + // In practice, this code path is "only" in the main thread of protoc, and + // it is common knowledge that touching setenv in a library is asking for + // life-ruining bugs *anyways*. As such, there is a reasonable probability + // that there isn't another thread kicking environment variables at this + // moment. + +#ifdef _WIN32 + ::_putenv(y_absl::StrCat(io::Printer::kProtocCodegenTrace, "=yes").c_str()); +#else + ::setenv(io::Printer::kProtocCodegenTrace.data(), "yes", 0); +#endif } else { // Some other flag. Look it up in the generators list. - const GeneratorInfo* generator_info = - FindOrNull(generators_by_flag_name_, name); + const GeneratorInfo* generator_info = FindGeneratorByFlag(name); if (generator_info == nullptr && - (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) { + (plugin_prefix_.empty() || !y_absl::EndsWith(name, "_out"))) { // Check if it's a generator option flag. - generator_info = FindOrNull(generators_by_option_name_, name); + generator_info = FindGeneratorByOption(name); if (generator_info != nullptr) { TProtoStringType* parameters = &generator_parameters_[generator_info->flag_name]; @@ -1994,7 +2125,7 @@ CommandLineInterface::InterpretArgument(const TProtoStringType& name, parameters->append(","); } parameters->append(value); - } else if (HasPrefixString(name, "--") && HasSuffixString(name, "_opt")) { + } else if (y_absl::StartsWith(name, "--") && y_absl::EndsWith(name, "_opt")) { TProtoStringType* parameters = &plugin_parameters_[PluginName(plugin_prefix_, name)]; if (!parameters->empty()) { @@ -2109,7 +2240,10 @@ Parse PROTO_FILES and generate output based on the options given: defined in the given proto files. Groups share the same field number space with the parent message. Extension ranges are counted as - occupied fields numbers.)"; + occupied fields numbers. + --enable_codegen_trace Enables tracing which parts of protoc are + responsible for what codegen output. Not supported + by all backends or on all platforms.)"; if (!plugin_prefix_.empty()) { std::cout << R"( --plugin=EXECUTABLE Specifies a plugin executable to use. @@ -2122,16 +2256,15 @@ Parse PROTO_FILES and generate output based on the options given: the executable's own name differs.)"; } - for (GeneratorMap::iterator iter = generators_by_flag_name_.begin(); - iter != generators_by_flag_name_.end(); ++iter) { + for (const auto& kv : generators_by_flag_name_) { // FIXME(kenton): If the text is long enough it will wrap, which is ugly, // but fixing this nicely (e.g. splitting on spaces) is probably more // trouble than it's worth. std::cout << std::endl - << " " << iter->first << "=OUT_DIR " - << TProtoStringType(19 - iter->first.size(), + << " " << kv.first << "=OUT_DIR " + << TProtoStringType(19 - kv.first.size(), ' ') // Spaces for alignment. - << iter->second.help_text; + << kv.second.help_text; } std::cout << R"( @<filename> Read options and filenames from file. If a @@ -2163,7 +2296,8 @@ bool CommandLineInterface::EnforceProto3OptionalSupport( << codegen_name << " hasn't been updated to support optional fields in " "proto3. Please ask the owner of this code generator to " - "support proto3 optional."; + "support proto3 optional." + << std::endl; return false; } } @@ -2179,8 +2313,8 @@ bool CommandLineInterface::GenerateOutput( TProtoStringType error; if (output_directive.generator == nullptr) { // This is a plugin. - GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") && - HasSuffixString(output_directive.name, "_out")) + Y_ABSL_CHECK(y_absl::StartsWith(output_directive.name, "--") && + y_absl::EndsWith(output_directive.name, "_out")) << "Bad name for plugin generator: " << output_directive.name; TProtoStringType plugin_name = PluginName(plugin_prefix_, output_directive.name); @@ -2228,7 +2362,7 @@ bool CommandLineInterface::GenerateDependencyManifestFile( DiskSourceTree* source_tree) { FileDescriptorSet file_set; - std::set<const FileDescriptor*> already_seen; + y_absl::flat_hash_set<const FileDescriptor*> already_seen; for (int i = 0; i < parsed_files.size(); i++) { GetTransitiveDependencies(parsed_files[i], false, false, &already_seen, file_set.mutable_file()); @@ -2268,7 +2402,7 @@ bool CommandLineInterface::GenerateDependencyManifestFile( io::Printer printer(&out, '$'); for (int i = 0; i < output_filenames.size(); i++) { - printer.Print(output_filenames[i].c_str()); + printer.Print(output_filenames[i]); if (i == output_filenames.size() - 1) { printer.Print(":"); } else { @@ -2309,7 +2443,7 @@ bool CommandLineInterface::GeneratePluginOutput( } - std::set<const FileDescriptor*> already_seen; + y_absl::flat_hash_set<const FileDescriptor*> already_seen; for (int i = 0; i < parsed_files.size(); i++) { request.add_file_to_generate(parsed_files[i]->name()); GetTransitiveDependencies(parsed_files[i], @@ -2336,7 +2470,7 @@ bool CommandLineInterface::GeneratePluginOutput( TProtoStringType communicate_error; if (!subprocess.Communicate(request, &response, &communicate_error)) { - *error = strings::Substitute("$0: $1", plugin_name, communicate_error); + *error = y_absl::Substitute("$0: $1", plugin_name, communicate_error); return false; } @@ -2363,7 +2497,7 @@ bool CommandLineInterface::GeneratePluginOutput( current_output.reset(); current_output.reset(generator_context->Open(output_file.name())); } else if (current_output == nullptr) { - *error = strings::Substitute( + *error = y_absl::Substitute( "$0: First file chunk returned by plugin did not specify a file " "name.", plugin_name); @@ -2482,13 +2616,13 @@ bool CommandLineInterface::WriteDescriptorSet( const std::vector<const FileDescriptor*>& parsed_files) { FileDescriptorSet file_set; - std::set<const FileDescriptor*> already_seen; + y_absl::flat_hash_set<const FileDescriptor*> already_seen; if (!imports_in_descriptor_set_) { // Since we don't want to output transitive dependencies, but we do want // things to be in dependency order, add all dependencies that aren't in // parsed_files to already_seen. This will short circuit the recursion // in GetTransitiveDependencies. - std::set<const FileDescriptor*> to_output; + y_absl::flat_hash_set<const FileDescriptor*> to_output; to_output.insert(parsed_files.begin(), parsed_files.end()); for (int i = 0; i < parsed_files.size(); i++) { const FileDescriptor* file = parsed_files[i]; @@ -2546,7 +2680,7 @@ bool CommandLineInterface::WriteDescriptorSet( void CommandLineInterface::GetTransitiveDependencies( const FileDescriptor* file, bool include_json_name, bool include_source_code_info, - std::set<const FileDescriptor*>* already_seen, + y_absl::flat_hash_set<const FileDescriptor*>* already_seen, RepeatedPtrField<FileDescriptorProto>* output) { if (!already_seen->insert(file).second) { // Already saw this file. Skip. @@ -2570,6 +2704,20 @@ void CommandLineInterface::GetTransitiveDependencies( } } +const CommandLineInterface::GeneratorInfo* +CommandLineInterface::FindGeneratorByFlag(const TProtoStringType& name) const { + auto it = generators_by_flag_name_.find(name); + if (it == generators_by_flag_name_.end()) return nullptr; + return &it->second; +} + +const CommandLineInterface::GeneratorInfo* +CommandLineInterface::FindGeneratorByOption(const TProtoStringType& option) const { + auto it = generators_by_option_name_.find(option); + if (it == generators_by_option_name_.end()) return nullptr; + return &it->second; +} + namespace { // Utility function for PrintFreeFieldNumbers. @@ -2605,9 +2753,9 @@ namespace { // order of the nested messages is also preserved. typedef std::pair<int, int> FieldRange; void GatherOccupiedFieldRanges( - const Descriptor* descriptor, std::set<FieldRange>* ranges, + const Descriptor* descriptor, y_absl::btree_set<FieldRange>* ranges, std::vector<const Descriptor*>* nested_messages) { - std::set<const Descriptor*> groups; + y_absl::flat_hash_set<const Descriptor*> groups; for (int i = 0; i < descriptor->field_count(); ++i) { const FieldDescriptor* fd = descriptor->field(i); ranges->insert(FieldRange(fd->number(), fd->number() + 1)); @@ -2639,30 +2787,29 @@ void GatherOccupiedFieldRanges( // Actually prints the formatted free field numbers for given message name and // occupied ranges. void FormatFreeFieldNumbers(const TProtoStringType& name, - const std::set<FieldRange>& ranges) { + const y_absl::btree_set<FieldRange>& ranges) { TProtoStringType output; - StringAppendF(&output, "%-35s free:", name.c_str()); + y_absl::StrAppendFormat(&output, "%-35s free:", name.c_str()); int next_free_number = 1; - for (std::set<FieldRange>::const_iterator i = ranges.begin(); - i != ranges.end(); ++i) { + for (const auto& range : ranges) { // This happens when groups re-use parent field numbers, in which // case we skip the FieldRange entirely. - if (next_free_number >= i->second) continue; + if (next_free_number >= range.second) continue; - if (next_free_number < i->first) { - if (next_free_number + 1 == i->first) { + if (next_free_number < range.first) { + if (next_free_number + 1 == range.first) { // Singleton - StringAppendF(&output, " %d", next_free_number); + y_absl::StrAppendFormat(&output, " %d", next_free_number); } else { // Range - StringAppendF(&output, " %d-%d", next_free_number, - i->first - 1); + y_absl::StrAppendFormat(&output, " %d-%d", next_free_number, + range.first - 1); } } - next_free_number = i->second; + next_free_number = range.second; } if (next_free_number <= FieldDescriptor::kMaxNumber) { - StringAppendF(&output, " %d-INF", next_free_number); + y_absl::StrAppendFormat(&output, " %d-INF", next_free_number); } std::cout << output << std::endl; } @@ -2670,7 +2817,7 @@ void FormatFreeFieldNumbers(const TProtoStringType& name, } // namespace void CommandLineInterface::PrintFreeFieldNumbers(const Descriptor* descriptor) { - std::set<FieldRange> ranges; + y_absl::btree_set<FieldRange> ranges; std::vector<const Descriptor*> nested_messages; GatherOccupiedFieldRanges(descriptor, &ranges, &nested_messages); |