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
15namespace dart {
16
17DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings.");
18DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors.");
19
20StringPtr Report::PrependSnippet(Kind kind,
21 const Script& script,
22 TokenPosition token_pos,
23 bool report_after_token,
24 const String& message) {
25 const char* message_header;
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
95void Report::LongJump(const Error& error) {
96 Thread::Current()->long_jump_base()->Jump(1, error);
97 UNREACHABLE();
98}
99
100void 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
112void 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
132void 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
144void 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