// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "vm/report.h" #include "vm/code_patcher.h" #include "vm/exceptions.h" #include "vm/flags.h" #include "vm/longjump.h" #include "vm/object.h" #include "vm/stack_frame.h" #include "vm/symbols.h" namespace dart { DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); StringPtr Report::PrependSnippet(Kind kind, const Script& script, TokenPosition token_pos, bool report_after_token, const String& message) { const char* message_header; switch (kind) { case kWarning: message_header = "warning"; break; case kError: message_header = "error"; break; case kBailout: message_header = "bailout"; break; default: message_header = ""; UNREACHABLE(); } String& result = String::Handle(); if (!script.IsNull() && script.HasSource()) { const String& script_url = String::Handle(script.url()); intptr_t line, column; if (script.GetTokenLocation(token_pos, &line, &column)) { const intptr_t token_len = script.GetTokenLength(token_pos); if (report_after_token) { column += token_len < 0 ? 1 : token_len; } // Allocate formatted strings in old space as they may be created during // optimizing compilation. Those strings are created rarely and should not // polute old space. result = String::NewFormatted( Heap::kOld, "'%s': %s: line %" Pd " pos %" Pd ": ", script_url.ToCString(), message_header, line, column); // Append the formatted error or warning message. const Array& strs = Array::Handle(Array::New(6, Heap::kOld)); strs.SetAt(0, result); strs.SetAt(1, message); // Append the source line. const String& script_line = String::Handle(script.GetLine(line, Heap::kOld)); ASSERT(!script_line.IsNull()); strs.SetAt(2, Symbols::NewLine()); strs.SetAt(3, script_line); strs.SetAt(4, Symbols::NewLine()); // Append the column marker. const String& column_line = String::Handle(String::NewFormatted( Heap::kOld, "%*s\n", static_cast(column), "^")); strs.SetAt(5, column_line); result = String::ConcatAll(strs, Heap::kOld); } else { // Token position is unknown. result = String::NewFormatted( Heap::kOld, "'%s': %s: ", script_url.ToCString(), message_header); result = String::Concat(result, message, Heap::kOld); } } else { // Script is unknown. // Append the formatted error or warning message. result = String::NewFormatted(Heap::kOld, "%s: ", message_header); result = String::Concat(result, message, Heap::kOld); } return result.ptr(); } void Report::LongJump(const Error& error) { Thread::Current()->long_jump_base()->Jump(1, error); UNREACHABLE(); } void Report::LongJumpF(const Error& prev_error, const Script& script, TokenPosition token_pos, const char* format, ...) { va_list args; va_start(args, format); LongJumpV(prev_error, script, token_pos, format, args); va_end(args); UNREACHABLE(); } void Report::LongJumpV(const Error& prev_error, const Script& script, TokenPosition token_pos, const char* format, va_list args) { // If an isolate is being killed a [UnwindError] will be propagated up the // stack. In such a case we cannot wrap the unwind error in a new // [LanguageError]. Instead we simply continue propagating the [UnwindError] // upwards. if (prev_error.IsUnwindError()) { LongJump(prev_error); UNREACHABLE(); } const Error& error = Error::Handle(LanguageError::NewFormattedV( prev_error, script, token_pos, Report::AtLocation, kError, Heap::kOld, format, args)); LongJump(error); UNREACHABLE(); } void Report::MessageF(Kind kind, const Script& script, TokenPosition token_pos, bool report_after_token, const char* format, ...) { va_list args; va_start(args, format); MessageV(kind, script, token_pos, report_after_token, format, args); va_end(args); } void Report::MessageV(Kind kind, const Script& script, TokenPosition token_pos, bool report_after_token, const char* format, va_list args) { if (kind < kError) { // Reporting a warning. if (FLAG_silent_warnings) { return; } if (!FLAG_warning_as_error) { const String& msg = String::Handle(String::NewFormattedV(format, args)); const String& snippet_msg = String::Handle( PrependSnippet(kind, script, token_pos, report_after_token, msg)); OS::PrintErr("%s", snippet_msg.ToCString()); return; } } // Reporting an error (or a warning as error). const Error& error = Error::Handle(LanguageError::NewFormattedV( Error::Handle(), // No previous error. script, token_pos, report_after_token, kind, Heap::kOld, format, args)); LongJump(error); UNREACHABLE(); } } // namespace dart