1 | // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "vm/report.h" |
6 | |
7 | #include "vm/code_patcher.h" |
8 | #include "vm/exceptions.h" |
9 | #include "vm/flags.h" |
10 | #include "vm/longjump.h" |
11 | #include "vm/object.h" |
12 | #include "vm/stack_frame.h" |
13 | #include "vm/symbols.h" |
14 | |
15 | namespace dart { |
16 | |
17 | DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings." ); |
18 | DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors." ); |
19 | |
20 | StringPtr Report::PrependSnippet(Kind kind, |
21 | const Script& script, |
22 | TokenPosition token_pos, |
23 | bool report_after_token, |
24 | const String& message) { |
25 | const char* ; |
26 | switch (kind) { |
27 | case kWarning: |
28 | message_header = "warning" ; |
29 | break; |
30 | case kError: |
31 | message_header = "error" ; |
32 | break; |
33 | case kBailout: |
34 | message_header = "bailout" ; |
35 | break; |
36 | default: |
37 | message_header = "" ; |
38 | UNREACHABLE(); |
39 | } |
40 | String& result = String::Handle(); |
41 | if (!script.IsNull() && !String::Handle(script.Source()).IsNull()) { |
42 | const String& script_url = String::Handle(script.url()); |
43 | if (token_pos.IsReal()) { |
44 | intptr_t line, column, token_len; |
45 | script.GetTokenLocation(token_pos, &line, &column, &token_len); |
46 | if (report_after_token) { |
47 | column += token_len; |
48 | } |
49 | // Only report the line position if we have the original source. We still |
50 | // need to get a valid column so that we can report the ^ mark below the |
51 | // snippet. |
52 | // Allocate formatted strings in old space as they may be created during |
53 | // optimizing compilation. Those strings are created rarely and should not |
54 | // polute old space. |
55 | if (script.HasSource()) { |
56 | result = String::NewFormatted( |
57 | Heap::kOld, "'%s': %s: line %" Pd " pos %" Pd ": " , |
58 | script_url.ToCString(), message_header, line, column); |
59 | } else { |
60 | result = |
61 | String::NewFormatted(Heap::kOld, "'%s': %s: line %" Pd ": " , |
62 | script_url.ToCString(), message_header, line); |
63 | } |
64 | // Append the formatted error or warning message. |
65 | const Array& strs = Array::Handle(Array::New(6, Heap::kOld)); |
66 | strs.SetAt(0, result); |
67 | strs.SetAt(1, message); |
68 | // Append the source line. |
69 | const String& script_line = |
70 | String::Handle(script.GetLine(line, Heap::kOld)); |
71 | ASSERT(!script_line.IsNull()); |
72 | strs.SetAt(2, Symbols::NewLine()); |
73 | strs.SetAt(3, script_line); |
74 | strs.SetAt(4, Symbols::NewLine()); |
75 | // Append the column marker. |
76 | const String& column_line = String::Handle(String::NewFormatted( |
77 | Heap::kOld, "%*s\n" , static_cast<int>(column), "^" )); |
78 | strs.SetAt(5, column_line); |
79 | result = String::ConcatAll(strs, Heap::kOld); |
80 | } else { |
81 | // Token position is unknown. |
82 | result = String::NewFormatted( |
83 | Heap::kOld, "'%s': %s: " , script_url.ToCString(), message_header); |
84 | result = String::Concat(result, message, Heap::kOld); |
85 | } |
86 | } else { |
87 | // Script is unknown. |
88 | // Append the formatted error or warning message. |
89 | result = String::NewFormatted(Heap::kOld, "%s: " , message_header); |
90 | result = String::Concat(result, message, Heap::kOld); |
91 | } |
92 | return result.raw(); |
93 | } |
94 | |
95 | void Report::LongJump(const Error& error) { |
96 | Thread::Current()->long_jump_base()->Jump(1, error); |
97 | UNREACHABLE(); |
98 | } |
99 | |
100 | void Report::LongJumpF(const Error& prev_error, |
101 | const Script& script, |
102 | TokenPosition token_pos, |
103 | const char* format, |
104 | ...) { |
105 | va_list args; |
106 | va_start(args, format); |
107 | LongJumpV(prev_error, script, token_pos, format, args); |
108 | va_end(args); |
109 | UNREACHABLE(); |
110 | } |
111 | |
112 | void Report::LongJumpV(const Error& prev_error, |
113 | const Script& script, |
114 | TokenPosition token_pos, |
115 | const char* format, |
116 | va_list args) { |
117 | // If an isolate is being killed a [UnwindError] will be propagated up the |
118 | // stack. In such a case we cannot wrap the unwind error in a new |
119 | // [LanguageError]. Instead we simply continue propagating the [UnwindError] |
120 | // upwards. |
121 | if (prev_error.IsUnwindError()) { |
122 | LongJump(prev_error); |
123 | UNREACHABLE(); |
124 | } |
125 | const Error& error = Error::Handle(LanguageError::NewFormattedV( |
126 | prev_error, script, token_pos, Report::AtLocation, kError, Heap::kOld, |
127 | format, args)); |
128 | LongJump(error); |
129 | UNREACHABLE(); |
130 | } |
131 | |
132 | void Report::MessageF(Kind kind, |
133 | const Script& script, |
134 | TokenPosition token_pos, |
135 | bool report_after_token, |
136 | const char* format, |
137 | ...) { |
138 | va_list args; |
139 | va_start(args, format); |
140 | MessageV(kind, script, token_pos, report_after_token, format, args); |
141 | va_end(args); |
142 | } |
143 | |
144 | void Report::MessageV(Kind kind, |
145 | const Script& script, |
146 | TokenPosition token_pos, |
147 | bool report_after_token, |
148 | const char* format, |
149 | va_list args) { |
150 | if (kind < kError) { |
151 | // Reporting a warning. |
152 | if (FLAG_silent_warnings) { |
153 | return; |
154 | } |
155 | if (!FLAG_warning_as_error) { |
156 | const String& msg = String::Handle(String::NewFormattedV(format, args)); |
157 | const String& snippet_msg = String::Handle( |
158 | PrependSnippet(kind, script, token_pos, report_after_token, msg)); |
159 | OS::PrintErr("%s" , snippet_msg.ToCString()); |
160 | return; |
161 | } |
162 | } |
163 | // Reporting an error (or a warning as error). |
164 | const Error& error = Error::Handle(LanguageError::NewFormattedV( |
165 | Error::Handle(), // No previous error. |
166 | script, token_pos, report_after_token, kind, Heap::kOld, format, args)); |
167 | LongJump(error); |
168 | UNREACHABLE(); |
169 | } |
170 | |
171 | } // namespace dart |
172 | |