[fidlc] Sharing error formatting in ErrorReporter
Test: unit tests, no expected behavior change
Change-Id: I2cfd3488ed56e0e887d125b46b545dca26bee17f
diff --git a/system/host/fidl/include/fidl/error_reporter.h b/system/host/fidl/include/fidl/error_reporter.h
index c323ce2..7816742 100644
--- a/system/host/fidl/include/fidl/error_reporter.h
+++ b/system/host/fidl/include/fidl/error_reporter.h
@@ -8,11 +8,17 @@
#include <string>
#include <vector>
+#include "source_location.h"
+#include "string_view.h"
+#include "token.h"
+
namespace fidl {
class ErrorReporter {
public:
- void ReportError(std::string error);
+ void ReportError(const SourceLocation& location, StringView message);
+ void ReportError(const Token& token, StringView message);
+ void ReportError(StringView message);
void PrintReports();
const std::vector<std::string>& errors() const { return errors_; };
diff --git a/system/host/fidl/lib/error_reporter.cpp b/system/host/fidl/lib/error_reporter.cpp
index 1779088..72df693 100644
--- a/system/host/fidl/lib/error_reporter.cpp
+++ b/system/host/fidl/lib/error_reporter.cpp
@@ -3,16 +3,90 @@
// found in the LICENSE file.
#include "fidl/error_reporter.h"
+#include "fidl/source_location.h"
+#include "fidl/string_view.h"
+#include "fidl/token.h"
namespace fidl {
-void ErrorReporter::ReportError(std::string error) {
+std::string MakeSquiggle(const std::string& surrounding_line, int column) {
+ std::string squiggle;
+ for (int i = 0; i < column; i++) {
+ switch (surrounding_line[i]) {
+ case '\t':
+ squiggle.push_back('\t');
+ default:
+ squiggle.push_back(' ');
+ }
+ }
+ squiggle.push_back('^');
+ return squiggle;
+}
+
+std::string FormatError(const SourceLocation& location, StringView message, size_t squiggle_size = 0u) {
+ SourceFile::Position position;
+ std::string surrounding_line = location.SourceLine(&position);
+
+ std::string squiggle = MakeSquiggle(surrounding_line, position.column);
+ if (squiggle_size != 0u) {
+ --squiggle_size;
+ }
+ squiggle += std::string(squiggle_size, '~');
+ // Some tokens (like string literals) can span multiple
+ // lines. Truncate the string to just one line at most. The
+ // containing line contains a newline, so drop it when
+ // comparing sizes.
+ size_t line_size = surrounding_line.size() - 1;
+ if (squiggle.size() > line_size) {
+ squiggle.resize(line_size);
+ }
+
+ // Many editors and IDEs recognize errors in the form of
+ // filename:linenumber:column: error: descriptive-test-here\n
+ std::string error = location.position();
+ error.append(": error: ");
+ error.append(message);
+ error.push_back('\n');
+ error.append(surrounding_line);
+ error.append(squiggle);
+
+ return error;
+}
+
+// ReportError records an error with the location, message, source line, and
+// position indicator.
+//
+// filename:line:col: error: message
+// sourceline
+// ^
+void ErrorReporter::ReportError(const SourceLocation& location, StringView message) {
+ auto error = FormatError(location, message);
+ errors_.push_back(std::move(error));
+}
+
+// ReportError records an error with the location, message, source line,
+// position indicator, and tildes under the token reported.
+//
+// filename:line:col: error: message
+// sourceline
+// ^~~~
+void ErrorReporter::ReportError(const Token& token, StringView message) {
+ auto token_location = token.location();
+ auto token_data = token_location.data();
+ auto error = FormatError(token_location, message, token_data.size());
+ errors_.push_back(std::move(error));
+}
+
+// ReportError records the provided message.
+void ErrorReporter::ReportError(StringView message) {
+ std::string error("error: ");
+ error.append(message);
errors_.push_back(std::move(error));
}
void ErrorReporter::PrintReports() {
for (const auto& error : errors_) {
- fprintf(stderr, "%s", error.data());
+ fprintf(stderr, "%s\n", error.data());
}
}
diff --git a/system/host/fidl/lib/flat_ast.cpp b/system/host/fidl/lib/flat_ast.cpp
index 369cb5f..f36ccd4 100644
--- a/system/host/fidl/lib/flat_ast.cpp
+++ b/system/host/fidl/lib/flat_ast.cpp
@@ -365,16 +365,12 @@
}
bool Library::Fail(StringView message) {
- auto formatted_message = std::string(message) + "\n";
- error_reporter_->ReportError(std::move(formatted_message));
+ error_reporter_->ReportError(message);
return false;
}
bool Library::Fail(const SourceLocation& location, StringView message) {
- // Many editors and IDEs recognize errors in the form of
- // filename:linenumber:column: error: descriptive-test-here\n
- auto formatted_message = location.position() + ": error: " + std::string(message) + "\n";
- error_reporter_->ReportError(std::move(formatted_message));
+ error_reporter_->ReportError(location, message);
return false;
}
diff --git a/system/host/fidl/lib/parser.cpp b/system/host/fidl/lib/parser.cpp
index 6d2ba77..e7a39fd 100644
--- a/system/host/fidl/lib/parser.cpp
+++ b/system/host/fidl/lib/parser.cpp
@@ -79,59 +79,13 @@
return true;
}
-std::string MakeSquiggle(const std::string& surrounding_line, int column) {
- std::string squiggle;
- for (int i = 0; i < column - 1; i++) {
- switch (surrounding_line[i]) {
- case '\t':
- squiggle += "\t";
- default:
- squiggle += " ";
- }
- }
- squiggle += "^";
- return squiggle;
-}
-
decltype(nullptr) Parser::Fail() {
return Fail("found unexpected token");
}
decltype(nullptr) Parser::Fail(StringView message) {
if (ok_) {
- auto token_location = last_token_.location();
- auto token_data = token_location.data();
-
- SourceFile::Position position;
- std::string surrounding_line = token_location.SourceLine(&position);
- auto line_number = std::to_string(position.line);
- auto column_number = std::to_string(position.column);
-
- std::string squiggle = MakeSquiggle(surrounding_line, position.column);
- size_t squiggle_size = token_data.size();
- if (squiggle_size != 0u) {
- --squiggle_size;
- }
- squiggle += std::string(squiggle_size, '~');
- // Some tokens (like string literals) can span multiple
- // lines. Truncate the string to just one line at most. The
- // containing line contains a newline, so drop it when
- // comparing sizes.
- size_t line_size = surrounding_line.size() - 1;
- if (squiggle.size() > line_size) {
- squiggle.resize(line_size);
- }
-
- // Many editors and IDEs recognize errors in the form of
- // filename:linenumber:column: error: descriptive-test-here\n
- std::string error = token_location.position();
- error += ": error: ";
- error += message;
- error += "\n";
- error += surrounding_line;
- error += squiggle + "\n";
-
- error_reporter_->ReportError(std::move(error));
+ error_reporter_->ReportError(last_token_, std::move(message));
ok_ = false;
}
return nullptr;
diff --git a/system/utest/fidl-compiler/using_tests.cpp b/system/utest/fidl-compiler/using_tests.cpp
index e6d4a37..5b8c6c7 100644
--- a/system/utest/fidl-compiler/using_tests.cpp
+++ b/system/utest/fidl-compiler/using_tests.cpp
@@ -93,11 +93,8 @@
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(1, errors.size());
- // TODO(pascal): Refactor. We should check the error message, not
- // necessarily the formatted message with filename:linenum:colnum. Consider
- // introducing ASSERT_STR_CONTAINS.
- ASSERT_STR_EQ(errors[0].c_str(),
- "uzing.fidl:7:2: error: Unknown dependent library fidl.test.uzing.dependent. Did you require it with `using`?\n");
+ ASSERT_STR_STR(errors[0].c_str(),
+ "Unknown dependent library fidl.test.uzing.dependent. Did you require it with `using`?");
END_TEST;
}
@@ -124,11 +121,8 @@
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(1, errors.size());
- // TODO(pascal): Refactor. We should check the error message, not
- // necessarily the formatted message with filename:linenum:colnum. Consider
- // introducing ASSERT_STR_CONTAINS.
- ASSERT_STR_EQ(errors[0].c_str(),
- "Library fidl.test.uzing.dependent already imported. Did you require it twice?\n");
+ ASSERT_STR_STR(errors[0].c_str(),
+ "Library fidl.test.uzing.dependent already imported. Did you require it twice?");
END_TEST;
}