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