1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "fidl/error_reporter.h"
6 #include "fidl/source_location.h"
7 #include "fidl/string_view.h"
8 #include "fidl/token.h"
9
10 namespace fidl {
11
MakeSquiggle(const std::string & surrounding_line,int column)12 std::string MakeSquiggle(const std::string& surrounding_line, int column) {
13 std::string squiggle;
14 for (int i = 0; i < column; i++) {
15 switch (surrounding_line[i]) {
16 case '\t':
17 squiggle.push_back('\t');
18 default:
19 squiggle.push_back(' ');
20 }
21 }
22 squiggle.push_back('^');
23 return squiggle;
24 }
25
Format(std::string qualifier,const SourceLocation & location,StringView message,size_t squiggle_size=0u)26 std::string Format(std::string qualifier, const SourceLocation& location,
27 StringView message, size_t squiggle_size = 0u) {
28 SourceFile::Position position;
29 std::string surrounding_line = location.SourceLine(&position);
30
31 std::string squiggle = MakeSquiggle(surrounding_line, position.column);
32 if (squiggle_size != 0u) {
33 --squiggle_size;
34 }
35 squiggle += std::string(squiggle_size, '~');
36 // Some tokens (like string literals) can span multiple
37 // lines. Truncate the string to just one line at most. The
38 // containing line contains a newline, so drop it when
39 // comparing sizes.
40 size_t line_size = surrounding_line.size() - 1;
41 if (squiggle.size() > line_size) {
42 squiggle.resize(line_size);
43 }
44
45 // Many editors and IDEs recognize errors in the form of
46 // filename:linenumber:column: error: descriptive-test-here\n
47 std::string error = location.position();
48 error.append(": ");
49 error.append(qualifier);
50 error.append(": ");
51 error.append(message);
52 error.push_back('\n');
53 error.append(surrounding_line);
54 error.append(squiggle);
55
56 return error;
57 }
58
59 // ReportError records an error with the location, message, source line, and
60 // position indicator.
61 //
62 // filename:line:col: error: message
63 // sourceline
64 // ^
ReportError(const SourceLocation & location,StringView message)65 void ErrorReporter::ReportError(const SourceLocation& location, StringView message) {
66 auto error = Format("error", location, message);
67 errors_.push_back(std::move(error));
68 }
69
70 // ReportError records an error with the location, message, source line,
71 // position indicator, and tildes under the token reported.
72 //
73 // filename:line:col: error: message
74 // sourceline
75 // ^~~~
ReportError(const Token & token,StringView message)76 void ErrorReporter::ReportError(const Token& token, StringView message) {
77 auto token_location = token.location();
78 auto token_data = token_location.data();
79 auto error = Format("error", token_location, message, token_data.size());
80 errors_.push_back(std::move(error));
81 }
82
83 // ReportError records the provided message.
ReportError(StringView message)84 void ErrorReporter::ReportError(StringView message) {
85 std::string error("error: ");
86 error.append(message);
87 errors_.push_back(std::move(error));
88 }
89
90 // ReportWarning records a warning with the location, message, source line, and
91 // position indicator.
92 //
93 // filename:line:col: warning: message
94 // sourceline
95 // ^
ReportWarning(const SourceLocation & location,StringView message)96 void ErrorReporter::ReportWarning(const SourceLocation& location, StringView message) {
97 auto error = Format("warning", location, message);
98 warnings_.push_back(std::move(error));
99 }
100
PrintReports()101 void ErrorReporter::PrintReports() {
102 for (const auto& error : errors_) {
103 fprintf(stderr, "%s\n", error.data());
104 }
105 for (const auto& warning : warnings_) {
106 fprintf(stderr, "%s\n", warning.data());
107 }
108 }
109
110 } // namespace fidl
111