Skip to content

Commit

Permalink
Adds a flag to protoc called --error_format which specifies what
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
[email protected] committed Apr 15, 2009
1 parent 90bdae2 commit f663b16
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 6 deletions.
5 changes: 5 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
be normally except without a tag before each value (thus, they are
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++
* UnknownFieldSet now supports STL-like iteration.
* Message interface has method ParseFromBoundedZeroCopyStream() which parses
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@ Non-Google patch contributors:
* Solaris 10 + Sun Studio fix.
Alek Storm <[email protected]>
* Slicing support for repeated scalar fields for the Python API.
Oleg Smolsky <[email protected]>
* MS Visual Studio error format option.
40 changes: 34 additions & 6 deletions src/google/protobuf/compiler/command_line_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -132,25 +132,39 @@ void SetFdToBinaryMode(int fd) {
class CommandLineInterface::ErrorPrinter : public MultiFileErrorCollector,
public io::ErrorCollector {
public:
ErrorPrinter() {}
ErrorPrinter(ErrorFormat format) : format_(format) {}
~ErrorPrinter() {}

// implements MultiFileErrorCollector ------------------------------
void AddError(const string& filename, int line, int column,
const string& message) {

cerr << filename;

// Users typically expect 1-based line/column numbers, so we add 1
// to each here.
cerr << filename;
if (line != -1) {
cerr << ":" << (line + 1) << ":" << (column + 1);
// Allow for both GCC- and Visual-Studio-compatible output.
switch (format_) {
case CommandLineInterface::ERROR_FORMAT_GCC:
cerr << ":" << (line + 1) << ":" << (column + 1);
break;
case CommandLineInterface::ERROR_FORMAT_MSVS:
cerr << "(" << (line + 1) << ") : error in column=" << (column + 1);
break;
}
}

cerr << ": " << message << endl;
}

// implements io::ErrorCollector -----------------------------------
void AddError(int line, int column, const string& message) {
AddError("input", line, column, message);
}

private:
const ErrorFormat format_;
};

// -------------------------------------------------------------------
Expand Down Expand Up @@ -294,6 +308,7 @@ CommandLineInterface::ErrorReportingFileOutput::~ErrorReportingFileOutput() {

CommandLineInterface::CommandLineInterface()
: mode_(MODE_COMPILE),
error_format_(ERROR_FORMAT_GCC),
imports_in_descriptor_set_(false),
disallow_services_(false),
inputs_are_proto_path_relative_(false) {}
Expand Down Expand Up @@ -326,7 +341,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) {
}

// Allocate the Importer.
ErrorPrinter error_collector;
ErrorPrinter error_collector(error_format_);
Importer importer(&source_tree, &error_collector);

vector<const FileDescriptor*> parsed_files;
Expand Down Expand Up @@ -657,6 +672,16 @@ bool CommandLineInterface::InterpretArgument(const string& name,

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 {
// Some other flag. Look it up in the generators list.
GeneratorMap::const_iterator iter = generators_.find(name);
Expand Down Expand Up @@ -722,7 +747,10 @@ void CommandLineInterface::PrintHelpText() {
" the input files to FILE.\n"
" --include_imports When using --descriptor_set_out, also include\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();
iter != generators_.end(); ++iter) {
Expand Down Expand Up @@ -788,7 +816,7 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) {

if (mode_ == MODE_ENCODE) {
// Input is text.
ErrorPrinter error_collector;
ErrorPrinter error_collector(error_format_);
TextFormat::Parser parser;
parser.RecordErrorsTo(&error_collector);
parser.AllowPartialMessage(true);
Expand Down
7 changes: 7 additions & 0 deletions src/google/protobuf/compiler/command_line_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,13 @@ class LIBPROTOC_EXPORT CommandLineInterface {

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<string> input_files_; // Names of the input proto files.

Expand Down
53 changes: 53 additions & 0 deletions src/google/protobuf/compiler/command_line_interface_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,59 @@ TEST_F(CommandLineInterfaceTest, HelpText) {
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

Expand Down

0 comments on commit f663b16

Please sign in to comment.