Commit f663b160 authored by kenton@google.com's avatar kenton@google.com

Adds a flag to protoc called --error_format which specifies what

convention to use when printing errors.  Default is GCC, but Microsoft
Visual Studio is another option.  This allows errors to be clickable in
the MSVS error log.
parent 90bdae22
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
be normally except without a tag before each value (thus, they are be normally except without a tag before each value (thus, they are
tightly "packed"). tightly "packed").
protoc
* --error_format=msvs option causes errors to be printed in Visual Studio
format, which should allow them to be clicked on in the build log to go
directly to the error location.
C++ C++
* UnknownFieldSet now supports STL-like iteration. * UnknownFieldSet now supports STL-like iteration.
* Message interface has method ParseFromBoundedZeroCopyStream() which parses * Message interface has method ParseFromBoundedZeroCopyStream() which parses
......
...@@ -55,3 +55,5 @@ Non-Google patch contributors: ...@@ -55,3 +55,5 @@ Non-Google patch contributors:
* Solaris 10 + Sun Studio fix. * Solaris 10 + Sun Studio fix.
Alek Storm <alek.storm@gmail.com> Alek Storm <alek.storm@gmail.com>
* Slicing support for repeated scalar fields for the Python API. * Slicing support for repeated scalar fields for the Python API.
Oleg Smolsky <oleg.smolsky@gmail.com>
* MS Visual Studio error format option.
...@@ -132,18 +132,29 @@ void SetFdToBinaryMode(int fd) { ...@@ -132,18 +132,29 @@ void SetFdToBinaryMode(int fd) {
class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector, class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
public io::ErrorCollector { public io::ErrorCollector {
public: public:
ErrorPrinter() {} ErrorPrinter(ErrorFormat format) : format_(format) {}
~ErrorPrinter() {} ~ErrorPrinter() {}
// implements MultiFileErrorCollector ------------------------------ // implements MultiFileErrorCollector ------------------------------
void AddError(const string& filename, int line, int column, void AddError(const string& filename, int line, int column,
const string& message) { const string& message) {
cerr << filename;
// Users typically expect 1-based line/column numbers, so we add 1 // Users typically expect 1-based line/column numbers, so we add 1
// to each here. // to each here.
cerr << filename;
if (line != -1) { if (line != -1) {
// Allow for both GCC- and Visual-Studio-compatible output.
switch (format_) {
case CommandLineInterface::ERROR_FORMAT_GCC:
cerr << ":" << (line + 1) << ":" << (column + 1); cerr << ":" << (line + 1) << ":" << (column + 1);
break;
case CommandLineInterface::ERROR_FORMAT_MSVS:
cerr << "(" << (line + 1) << ") : error in column=" << (column + 1);
break;
}
} }
cerr << ": " << message << endl; cerr << ": " << message << endl;
} }
...@@ -151,6 +162,9 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector, ...@@ -151,6 +162,9 @@ class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
void AddError(int line, int column, const string& message) { void AddError(int line, int column, const string& message) {
AddError("input", line, column, message); AddError("input", line, column, message);
} }
private:
const ErrorFormat format_;
}; };
// ------------------------------------------------------------------- // -------------------------------------------------------------------
...@@ -294,6 +308,7 @@ CommandLineInterface::ErrorReportingFileOutput::~ErrorReportingFileOutput() { ...@@ -294,6 +308,7 @@ CommandLineInterface::ErrorReportingFileOutput::~ErrorReportingFileOutput() {
CommandLineInterface::CommandLineInterface() CommandLineInterface::CommandLineInterface()
: mode_(MODE_COMPILE), : mode_(MODE_COMPILE),
error_format_(ERROR_FORMAT_GCC),
imports_in_descriptor_set_(false), imports_in_descriptor_set_(false),
disallow_services_(false), disallow_services_(false),
inputs_are_proto_path_relative_(false) {} inputs_are_proto_path_relative_(false) {}
...@@ -326,7 +341,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { ...@@ -326,7 +341,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
} }
// Allocate the Importer. // Allocate the Importer.
ErrorPrinter error_collector; ErrorPrinter error_collector(error_format_);
Importer importer(&source_tree, &error_collector); Importer importer(&source_tree, &error_collector);
vector<const FileDescriptor*> parsed_files; vector<const FileDescriptor*> parsed_files;
...@@ -657,6 +672,16 @@ bool CommandLineInterface::InterpretArgument(const string& name, ...@@ -657,6 +672,16 @@ bool CommandLineInterface::InterpretArgument(const string& name,
codec_type_ = value; codec_type_ = value;
} else if (name == "--error_format") {
if (value == "gcc") {
error_format_ = ERROR_FORMAT_GCC;
} else if (value == "msvs") {
error_format_ = ERROR_FORMAT_MSVS;
} else {
cerr << "Unknown error format: " << value << endl;
return false;
}
} else { } else {
// Some other flag. Look it up in the generators list. // Some other flag. Look it up in the generators list.
GeneratorMap::const_iterator iter = generators_.find(name); GeneratorMap::const_iterator iter = generators_.find(name);
...@@ -722,7 +747,10 @@ void CommandLineInterface::PrintHelpText() { ...@@ -722,7 +747,10 @@ void CommandLineInterface::PrintHelpText() {
" the input files to FILE.\n" " the input files to FILE.\n"
" --include_imports When using --descriptor_set_out, also include\n" " --include_imports When using --descriptor_set_out, also include\n"
" all dependencies of the input files in the\n" " all dependencies of the input files in the\n"
" set, so that the set is self-contained." << endl; " set, so that the set is self-contained.\n"
" --error_format=FORMAT Set the format in which to print errors.\n"
" FORMAT may be 'gcc' (the default) or 'msvs'\n"
" (Microsoft Visual Studio format)." << endl;
for (GeneratorMap::iterator iter = generators_.begin(); for (GeneratorMap::iterator iter = generators_.begin();
iter != generators_.end(); ++iter) { iter != generators_.end(); ++iter) {
...@@ -788,7 +816,7 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) { ...@@ -788,7 +816,7 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {
if (mode_ == MODE_ENCODE) { if (mode_ == MODE_ENCODE) {
// Input is text. // Input is text.
ErrorPrinter error_collector; ErrorPrinter error_collector(error_format_);
TextFormat::Parser parser; TextFormat::Parser parser;
parser.RecordErrorsTo(&error_collector); parser.RecordErrorsTo(&error_collector);
parser.AllowPartialMessage(true); parser.AllowPartialMessage(true);
......
...@@ -210,6 +210,13 @@ class LIBPROTOC_EXPORT CommandLineInterface { ...@@ -210,6 +210,13 @@ class LIBPROTOC_EXPORT CommandLineInterface {
Mode mode_; Mode mode_;
enum ErrorFormat {
ERROR_FORMAT_GCC, // GCC error output format (default).
ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs).
};
ErrorFormat error_format_;
vector<pair<string, string> > proto_path_; // Search path for proto files. vector<pair<string, string> > proto_path_; // Search path for proto files.
vector<string> input_files_; // Names of the input proto files. vector<string> input_files_; // Names of the input proto files.
......
...@@ -1047,6 +1047,59 @@ TEST_F(CommandLineInterfaceTest, HelpText) { ...@@ -1047,6 +1047,59 @@ TEST_F(CommandLineInterfaceTest, HelpText) {
ExpectErrorSubstring("Test error output."); ExpectErrorSubstring("Test error output.");
} }
TEST_F(CommandLineInterfaceTest, GccFormatErrors) {
// Test --error_format=gcc (which is the default, but we want to verify
// that it can be set explicitly).
RegisterGenerator("test_generator", "--test_out",
"output.test", "Test output.");
CreateTempFile("foo.proto",
"syntax = \"proto2\";\n"
"badsyntax\n");
Run("protocol_compiler --test_out=$tmpdir "
"--proto_path=$tmpdir --error_format=gcc foo.proto");
ExpectErrorText(
"foo.proto:2:1: Expected top-level statement (e.g. \"message\").\n");
}
TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) {
// Test --error_format=msvs
RegisterGenerator("test_generator", "--test_out",
"output.test", "Test output.");
CreateTempFile("foo.proto",
"syntax = \"proto2\";\n"
"badsyntax\n");
Run("protocol_compiler --test_out=$tmpdir "
"--proto_path=$tmpdir --error_format=msvs foo.proto");
ExpectErrorText(
"foo.proto(2) : error in column=1: Expected top-level statement "
"(e.g. \"message\").\n");
}
TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) {
// Test --error_format=msvs
RegisterGenerator("test_generator", "--test_out",
"output.test", "Test output.");
CreateTempFile("foo.proto",
"syntax = \"proto2\";\n"
"badsyntax\n");
Run("protocol_compiler --test_out=$tmpdir "
"--proto_path=$tmpdir --error_format=invalid foo.proto");
ExpectErrorText(
"Unknown error format: invalid\n");
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Flag parsing tests // Flag parsing tests
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment