summaryrefslogtreecommitdiffstats
path: root/contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc
diff options
context:
space:
mode:
authornechda <[email protected]>2024-08-29 23:50:27 +0300
committernechda <[email protected]>2024-08-30 00:05:25 +0300
commite10d6638f07a82edae3ea8197b9f5c0affcc07ea (patch)
tree571c38cec05813766a1ad290c9d51ce7ace52919 /contrib/libs/protoc/src/google/protobuf/compiler/command_line_interface.cc
parente79b38f2bbbf78d295d1901d2a79f898022d5224 (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.cc575
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);