refactor to use new snippet code and model
Major changes: - Remove old snippet rendering code and use the new stuff. - Introduce `span_label` method to add a label - Remove EndSpan mode and replace with a fn to get the last character of a span. - Stop using `Option<MultiSpan>` and just use an empty `MultiSpan` - and probably a bunch of other stuff :)
This commit is contained in:
parent
5b150cf0ca
commit
11dc974a38
@ -567,7 +567,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
|
||||
}
|
||||
config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
|
||||
};
|
||||
emitter.emit(None, msg, None, errors::Level::Fatal);
|
||||
emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Fatal);
|
||||
panic!(errors::FatalError);
|
||||
}
|
||||
|
||||
@ -578,7 +578,7 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
|
||||
}
|
||||
config::ErrorOutputType::Json => Box::new(JsonEmitter::basic()),
|
||||
};
|
||||
emitter.emit(None, msg, None, errors::Level::Warning);
|
||||
emitter.emit(&MultiSpan::new(), msg, None, errors::Level::Warning);
|
||||
}
|
||||
|
||||
// Err(0) means compilation was stopped, but no errors were found.
|
||||
|
@ -91,8 +91,9 @@ use std::thread;
|
||||
|
||||
use rustc::session::early_error;
|
||||
|
||||
use syntax::{ast, errors, diagnostics};
|
||||
use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
|
||||
use syntax::{ast, errors, diagnostic};
|
||||
use syntax::codemap::MultiSpan;
|
||||
use syntax::parse::{self, PResult};
|
||||
use syntax::errors::emitter::Emitter;
|
||||
use syntax::feature_gate::{GatedCfg, UnstableFeatures};
|
||||
use syntax::parse::{self, PResult, token};
|
||||
@ -136,7 +137,8 @@ pub fn run(args: Vec<String>) -> isize {
|
||||
None => {
|
||||
let mut emitter =
|
||||
errors::emitter::BasicEmitter::stderr(errors::ColorConfig::Auto);
|
||||
emitter.emit(None, &abort_msg(err_count), None, errors::Level::Fatal);
|
||||
emitter.emit(&MultiSpan::new(), &abort_msg(err_count), None,
|
||||
errors::Level::Fatal);
|
||||
exit_on_err();
|
||||
}
|
||||
}
|
||||
@ -379,7 +381,7 @@ fn check_cfg(sopts: &config::Options,
|
||||
match item.node {
|
||||
ast::MetaItemKind::List(ref pred, _) => {
|
||||
saw_invalid_predicate = true;
|
||||
emitter.emit(None,
|
||||
emitter.emit(&MultiSpan::new(),
|
||||
&format!("invalid predicate in --cfg command line argument: `{}`",
|
||||
pred),
|
||||
None,
|
||||
@ -1028,19 +1030,19 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
|
||||
// a .span_bug or .bug call has already printed what
|
||||
// it wants to print.
|
||||
if !value.is::<errors::ExplicitBug>() {
|
||||
emitter.emit(None, "unexpected panic", None, errors::Level::Bug);
|
||||
emitter.emit(&MultiSpan::new(), "unexpected panic", None, errors::Level::Bug);
|
||||
}
|
||||
|
||||
let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(),
|
||||
format!("we would appreciate a bug report: {}", BUG_REPORT_URL)];
|
||||
for note in &xs {
|
||||
emitter.emit(None, ¬e[..], None, errors::Level::Note)
|
||||
emitter.emit(&MultiSpan::new(), ¬e[..], None, errors::Level::Note)
|
||||
}
|
||||
if match env::var_os("RUST_BACKTRACE") {
|
||||
Some(val) => &val != "0",
|
||||
None => false,
|
||||
} {
|
||||
emitter.emit(None,
|
||||
emitter.emit(&MultiSpan::new(),
|
||||
"run with `RUST_BACKTRACE=1` for a backtrace",
|
||||
None,
|
||||
errors::Level::Note);
|
||||
|
@ -86,10 +86,6 @@ impl Emitter for ExpectErrorEmitter {
|
||||
lvl: Level) {
|
||||
remove_message(self, msg, lvl);
|
||||
}
|
||||
|
||||
fn custom_emit(&mut self, _sp: &RenderSpan, msg: &str, lvl: Level) {
|
||||
remove_message(self, msg, lvl);
|
||||
}
|
||||
}
|
||||
|
||||
fn errors(msgs: &[&str]) -> (Box<Emitter + Send>, usize) {
|
||||
|
@ -19,7 +19,7 @@ use llvm::SMDiagnosticRef;
|
||||
use {CrateTranslation, ModuleTranslation};
|
||||
use util::common::time;
|
||||
use util::common::path2cstr;
|
||||
use syntax::codemap;
|
||||
use syntax::codemap::{self, MultiSpan};
|
||||
use syntax::errors::{self, Handler, Level};
|
||||
use syntax::errors::emitter::Emitter;
|
||||
|
||||
@ -84,13 +84,13 @@ impl SharedEmitter {
|
||||
for diag in &*buffer {
|
||||
match diag.code {
|
||||
Some(ref code) => {
|
||||
handler.emit_with_code(None,
|
||||
handler.emit_with_code(&MultiSpan::new(),
|
||||
&diag.msg,
|
||||
&code[..],
|
||||
diag.lvl);
|
||||
},
|
||||
None => {
|
||||
handler.emit(None,
|
||||
handler.emit(&MultiSpan::new(),
|
||||
&diag.msg,
|
||||
diag.lvl);
|
||||
},
|
||||
@ -101,9 +101,12 @@ impl SharedEmitter {
|
||||
}
|
||||
|
||||
impl Emitter for SharedEmitter {
|
||||
fn emit(&mut self, sp: Option<&codemap::MultiSpan>,
|
||||
msg: &str, code: Option<&str>, lvl: Level) {
|
||||
assert!(sp.is_none(), "SharedEmitter doesn't support spans");
|
||||
fn emit(&mut self,
|
||||
sp: &codemap::MultiSpan,
|
||||
msg: &str,
|
||||
code: Option<&str>,
|
||||
lvl: Level) {
|
||||
assert!(sp.primary_span().is_none(), "SharedEmitter doesn't support spans");
|
||||
|
||||
self.buffer.lock().unwrap().push(Diagnostic {
|
||||
msg: msg.to_string(),
|
||||
@ -112,8 +115,8 @@ impl Emitter for SharedEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
fn custom_emit(&mut self, _sp: &errors::RenderSpan, _msg: &str, _lvl: Level) {
|
||||
bug!("SharedEmitter doesn't support custom_emit");
|
||||
fn emit_struct(&mut self, _db: &errors::DiagnosticBuilder) {
|
||||
bug!("SharedEmitter doesn't support emit_struct");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,6 +163,12 @@ pub const COMMAND_LINE_SP: Span = Span { lo: BytePos(0),
|
||||
expn_id: COMMAND_LINE_EXPN };
|
||||
|
||||
impl Span {
|
||||
/// Returns a new span representing just the end-point of this span
|
||||
pub fn end_point(self) -> Span {
|
||||
let lo = cmp::max(self.hi.0 - 1, self.lo.0);
|
||||
Span { lo: BytePos(lo), hi: self.hi, expn_id: self.expn_id}
|
||||
}
|
||||
|
||||
/// Returns `self` if `self` is not the dummy span, and `other` otherwise.
|
||||
pub fn substitute_dummy(self, other: Span) -> Span {
|
||||
if self.source_equal(&DUMMY_SP) { other } else { self }
|
||||
@ -794,7 +800,7 @@ impl CodeMap {
|
||||
/// Creates a new filemap and sets its line information.
|
||||
pub fn new_filemap_and_lines(&self, filename: &str, src: &str) -> Rc<FileMap> {
|
||||
let fm = self.new_filemap(filename.to_string(), src.to_owned());
|
||||
let mut byte_pos: u32 = 0;
|
||||
let mut byte_pos: u32 = fm.start_pos.0;
|
||||
for line in src.lines() {
|
||||
// register the start of this line
|
||||
fm.next_line(BytePos(byte_pos));
|
||||
@ -1126,7 +1132,9 @@ impl CodeMap {
|
||||
// numbers in Loc are 1-based, so we subtract 1 to get 0-based
|
||||
// lines.
|
||||
for line_index in lo.line-1 .. hi.line-1 {
|
||||
let line_len = lo.file.get_line(line_index).map(|s| s.len()).unwrap_or(0);
|
||||
let line_len = lo.file.get_line(line_index)
|
||||
.map(|s| s.chars().count())
|
||||
.unwrap_or(0);
|
||||
lines.push(LineInfo { line_index: line_index,
|
||||
start_col: start_col,
|
||||
end_col: CharPos::from_usize(line_len) });
|
||||
@ -1584,13 +1592,13 @@ mod tests {
|
||||
assert_eq!(file_lines.lines[0].line_index, 1);
|
||||
}
|
||||
|
||||
/// Given a string like " ^~~~~~~~~~~~ ", produces a span
|
||||
/// Given a string like " ~~~~~~~~~~~~ ", produces a span
|
||||
/// coverting that range. The idea is that the string has the same
|
||||
/// length as the input, and we uncover the byte positions. Note
|
||||
/// that this can span lines and so on.
|
||||
fn span_from_selection(input: &str, selection: &str) -> Span {
|
||||
assert_eq!(input.len(), selection.len());
|
||||
let left_index = selection.find('^').unwrap() as u32;
|
||||
let left_index = selection.find('~').unwrap() as u32;
|
||||
let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index);
|
||||
Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION }
|
||||
}
|
||||
@ -1601,7 +1609,7 @@ mod tests {
|
||||
fn span_to_snippet_and_lines_spanning_multiple_lines() {
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
|
||||
let selection = " \n ^~\n~~~\n~~~~~ \n \n";
|
||||
let selection = " \n ~~\n~~~\n~~~~~ \n \n";
|
||||
cm.new_filemap_and_lines("blork.rs", inputtext);
|
||||
let span = span_from_selection(inputtext, selection);
|
||||
|
||||
@ -1751,73 +1759,4 @@ r"blork2.rs:2:1: 2:12
|
||||
";
|
||||
assert_eq!(sstr, res_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t13() {
|
||||
// Test that collecting multiple spans into line-groups works correctly
|
||||
let cm = CodeMap::new();
|
||||
let inp = "_aaaaa__bbb\nvv\nw\nx\ny\nz\ncccccc__ddddee__";
|
||||
let sp1 = " ^~~~~ \n \n \n \n \n \n ";
|
||||
let sp2 = " \n \n \n \n \n^\n ";
|
||||
let sp3 = " ^~~\n~~\n \n \n \n \n ";
|
||||
let sp4 = " \n \n \n \n \n \n^~~~~~ ";
|
||||
let sp5 = " \n \n \n \n \n \n ^~~~ ";
|
||||
let sp6 = " \n \n \n \n \n \n ^~~~ ";
|
||||
let sp_trim = " \n \n \n \n \n \n ^~ ";
|
||||
let sp_merge = " \n \n \n \n \n \n ^~~~~~ ";
|
||||
let sp7 = " \n ^\n \n \n \n \n ";
|
||||
let sp8 = " \n \n^\n \n \n \n ";
|
||||
let sp9 = " \n \n \n^\n \n \n ";
|
||||
let sp10 = " \n \n \n \n^\n \n ";
|
||||
|
||||
let span = |sp, expected| {
|
||||
let sp = span_from_selection(inp, sp);
|
||||
assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected);
|
||||
sp
|
||||
};
|
||||
|
||||
cm.new_filemap_and_lines("blork.rs", inp);
|
||||
let sp1 = span(sp1, "aaaaa");
|
||||
let sp2 = span(sp2, "z");
|
||||
let sp3 = span(sp3, "bbb\nvv");
|
||||
let sp4 = span(sp4, "cccccc");
|
||||
let sp5 = span(sp5, "dddd");
|
||||
let sp6 = span(sp6, "ddee");
|
||||
let sp7 = span(sp7, "v");
|
||||
let sp8 = span(sp8, "w");
|
||||
let sp9 = span(sp9, "x");
|
||||
let sp10 = span(sp10, "y");
|
||||
let sp_trim = span(sp_trim, "ee");
|
||||
let sp_merge = span(sp_merge, "ddddee");
|
||||
|
||||
let spans = vec![sp5, sp2, sp4, sp9, sp10, sp7, sp3, sp8, sp1, sp6];
|
||||
|
||||
macro_rules! check_next {
|
||||
($groups: expr, $expected: expr) => ({
|
||||
let actual = $groups.next().map(|g|&g.spans[..]);
|
||||
let expected = $expected;
|
||||
println!("actual:\n{:?}\n", actual);
|
||||
println!("expected:\n{:?}\n", expected);
|
||||
assert_eq!(actual, expected.as_ref().map(|x|&x[..]));
|
||||
});
|
||||
}
|
||||
|
||||
let _groups = cm.group_spans(spans.clone());
|
||||
let it = &mut _groups.iter();
|
||||
|
||||
check_next!(it, Some([sp1, sp7, sp8, sp9, sp10, sp2]));
|
||||
// New group because we're exceeding MAX_HIGHLIGHT_LINES
|
||||
check_next!(it, Some([sp4, sp_merge]));
|
||||
check_next!(it, Some([sp3]));
|
||||
check_next!(it, None::<[Span; 0]>);
|
||||
|
||||
let _groups = cm.end_group_spans(spans);
|
||||
let it = &mut _groups.iter();
|
||||
|
||||
check_next!(it, Some([sp1, sp7, sp8, sp9, sp10, sp2]));
|
||||
// New group because we're exceeding MAX_HIGHLIGHT_LINES
|
||||
check_next!(it, Some([sp4, sp5, sp_trim]));
|
||||
check_next!(it, Some([sp3]));
|
||||
check_next!(it, None::<[Span; 0]>);
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ use diagnostics;
|
||||
use errors::{Level, RenderSpan, CodeSuggestion, DiagnosticBuilder};
|
||||
use errors::RenderSpan::*;
|
||||
use errors::Level::*;
|
||||
use errors::snippet::{RenderedLineKind, SnippetData, Style};
|
||||
|
||||
use std::{cmp, fmt};
|
||||
use std::io::prelude::*;
|
||||
@ -24,27 +25,15 @@ use std::rc::Rc;
|
||||
use term;
|
||||
|
||||
pub trait Emitter {
|
||||
fn emit(&mut self, span: Option<&MultiSpan>, msg: &str, code: Option<&str>, lvl: Level);
|
||||
fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, lvl: Level);
|
||||
fn emit(&mut self, span: &MultiSpan, msg: &str, code: Option<&str>, lvl: Level);
|
||||
|
||||
/// Emit a structured diagnostic.
|
||||
fn emit_struct(&mut self, db: &DiagnosticBuilder) {
|
||||
self.emit(db.span.as_ref(), &db.message, db.code.as_ref().map(|s| &**s), db.level);
|
||||
for child in &db.children {
|
||||
match child.render_span {
|
||||
Some(ref sp) => self.custom_emit(sp, &child.message, child.level),
|
||||
None => self.emit(child.span.as_ref(), &child.message, None, child.level),
|
||||
}
|
||||
}
|
||||
}
|
||||
fn emit_struct(&mut self, db: &DiagnosticBuilder);
|
||||
}
|
||||
|
||||
/// maximum number of lines we will print for each error; arbitrary.
|
||||
pub const MAX_HIGHLIGHT_LINES: usize = 6;
|
||||
|
||||
/// maximum number of lines we will print for each span; arbitrary.
|
||||
const MAX_SP_LINES: usize = 6;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum ColorConfig {
|
||||
Auto,
|
||||
@ -70,19 +59,23 @@ pub struct BasicEmitter {
|
||||
|
||||
impl Emitter for BasicEmitter {
|
||||
fn emit(&mut self,
|
||||
msp: Option<&MultiSpan>,
|
||||
msp: &MultiSpan,
|
||||
msg: &str,
|
||||
code: Option<&str>,
|
||||
lvl: Level) {
|
||||
assert!(msp.is_none(), "BasicEmitter can't handle spans");
|
||||
assert!(msp.primary_span().is_none(), "BasicEmitter can't handle spans");
|
||||
|
||||
if let Err(e) = print_diagnostic(&mut self.dst, "", lvl, msg, code) {
|
||||
panic!("failed to print diagnostics: {:?}", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn custom_emit(&mut self, _: &RenderSpan, _: &str, _: Level) {
|
||||
panic!("BasicEmitter can't handle custom_emit");
|
||||
fn emit_struct(&mut self, db: &DiagnosticBuilder) {
|
||||
self.emit(&db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level);
|
||||
for child in &db.children {
|
||||
assert!(child.render_span.is_none(), "BasicEmitter can't handle spans");
|
||||
self.emit(&child.span, &child.message, None, child.level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,33 +94,31 @@ pub struct EmitterWriter {
|
||||
dst: Destination,
|
||||
registry: Option<diagnostics::registry::Registry>,
|
||||
cm: Rc<codemap::CodeMap>,
|
||||
first: bool,
|
||||
}
|
||||
|
||||
impl Emitter for EmitterWriter {
|
||||
fn emit(&mut self,
|
||||
msp: Option<&MultiSpan>,
|
||||
msp: &MultiSpan,
|
||||
msg: &str,
|
||||
code: Option<&str>,
|
||||
lvl: Level) {
|
||||
let error = match msp.map(|s|(s.to_span_bounds(), s)) {
|
||||
Some((COMMAND_LINE_SP, msp)) => {
|
||||
self.emit_(&FileLine(msp.clone()), msg, code, lvl)
|
||||
},
|
||||
Some((DUMMY_SP, _)) | None => print_diagnostic(&mut self.dst, "", lvl, msg, code),
|
||||
Some((_, msp)) => self.emit_(&FullSpan(msp.clone()), msg, code, lvl),
|
||||
};
|
||||
|
||||
if let Err(e) = error {
|
||||
panic!("failed to print diagnostics: {:?}", e);
|
||||
}
|
||||
self.emit_multispan(msp, msg, code, lvl, true);
|
||||
}
|
||||
|
||||
fn custom_emit(&mut self,
|
||||
rsp: &RenderSpan,
|
||||
msg: &str,
|
||||
lvl: Level) {
|
||||
if let Err(e) = self.emit_(rsp, msg, None, lvl) {
|
||||
panic!("failed to print diagnostics: {:?}", e);
|
||||
fn emit_struct(&mut self, db: &DiagnosticBuilder) {
|
||||
self.emit_multispan(&db.span, &db.message,
|
||||
db.code.as_ref().map(|s| &**s), db.level, true);
|
||||
|
||||
for child in &db.children {
|
||||
match child.render_span {
|
||||
Some(ref sp) =>
|
||||
self.emit_renderspan(sp, &child.message,
|
||||
child.level),
|
||||
None =>
|
||||
self.emit_multispan(&child.span,
|
||||
&child.message, None, child.level, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -153,9 +144,10 @@ impl EmitterWriter {
|
||||
-> EmitterWriter {
|
||||
if color_config.use_color() {
|
||||
let dst = Destination::from_stderr();
|
||||
EmitterWriter { dst: dst, registry: registry, cm: code_map }
|
||||
EmitterWriter { dst: dst, registry: registry, cm: code_map, first: true }
|
||||
} else {
|
||||
EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map }
|
||||
EmitterWriter { dst: Raw(Box::new(io::stderr())),
|
||||
registry: registry, cm: code_map, first: true }
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,7 +155,49 @@ impl EmitterWriter {
|
||||
registry: Option<diagnostics::registry::Registry>,
|
||||
code_map: Rc<codemap::CodeMap>)
|
||||
-> EmitterWriter {
|
||||
EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map }
|
||||
EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, first: true }
|
||||
}
|
||||
|
||||
fn emit_multispan(&mut self,
|
||||
span: &MultiSpan,
|
||||
msg: &str,
|
||||
code: Option<&str>,
|
||||
lvl: Level,
|
||||
is_header: bool) {
|
||||
if is_header {
|
||||
if self.first {
|
||||
self.first = false;
|
||||
} else {
|
||||
match write!(self.dst, "\n") {
|
||||
Ok(_) => { }
|
||||
Err(e) => {
|
||||
panic!("failed to print diagnostics: {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let error = match span.primary_span() {
|
||||
Some(COMMAND_LINE_SP) => {
|
||||
self.emit_(&FileLine(span.clone()), msg, code, lvl)
|
||||
}
|
||||
Some(DUMMY_SP) | None => {
|
||||
print_diagnostic(&mut self.dst, "", lvl, msg, code)
|
||||
}
|
||||
Some(_) => {
|
||||
self.emit_(&FullSpan(span.clone()), msg, code, lvl)
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = error {
|
||||
panic!("failed to print diagnostics: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_renderspan(&mut self, sp: &RenderSpan, msg: &str, lvl: Level) {
|
||||
if let Err(e) = self.emit_(sp, msg, None, lvl) {
|
||||
panic!("failed to print diagnostics: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_(&mut self,
|
||||
@ -173,51 +207,43 @@ impl EmitterWriter {
|
||||
lvl: Level)
|
||||
-> io::Result<()> {
|
||||
let msp = rsp.span();
|
||||
let bounds = msp.to_span_bounds();
|
||||
let primary_span = msp.primary_span();
|
||||
|
||||
let ss = if bounds == COMMAND_LINE_SP {
|
||||
"<command line option>".to_string()
|
||||
} else if let EndSpan(_) = *rsp {
|
||||
let span_end = Span { lo: bounds.hi, hi: bounds.hi, expn_id: bounds.expn_id};
|
||||
self.cm.span_to_string(span_end)
|
||||
} else {
|
||||
self.cm.span_to_string(bounds)
|
||||
};
|
||||
|
||||
print_diagnostic(&mut self.dst, &ss[..], lvl, msg, code)?;
|
||||
match code {
|
||||
Some(code) if self.registry.as_ref()
|
||||
.and_then(|registry| registry.find_description(code)).is_some() =>
|
||||
{
|
||||
let code_with_explain = String::from("--explain ") + code;
|
||||
print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))?
|
||||
}
|
||||
_ => print_diagnostic(&mut self.dst, "", lvl, msg, code)?
|
||||
}
|
||||
|
||||
match *rsp {
|
||||
FullSpan(_) => {
|
||||
self.highlight_lines(msp, lvl)?;
|
||||
self.print_macro_backtrace(bounds)?;
|
||||
}
|
||||
EndSpan(_) => {
|
||||
self.end_highlight_lines(msp, lvl)?;
|
||||
self.print_macro_backtrace(bounds)?;
|
||||
if let Some(primary_span) = primary_span {
|
||||
self.print_macro_backtrace(primary_span)?;
|
||||
}
|
||||
}
|
||||
Suggestion(ref suggestion) => {
|
||||
self.highlight_suggestion(suggestion)?;
|
||||
self.print_macro_backtrace(bounds)?;
|
||||
if let Some(primary_span) = primary_span {
|
||||
self.print_macro_backtrace(primary_span)?;
|
||||
}
|
||||
}
|
||||
FileLine(..) => {
|
||||
// no source text in this case!
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(code) = code {
|
||||
if let Some(_) = self.registry.as_ref()
|
||||
.and_then(|registry| registry.find_description(code)) {
|
||||
print_diagnostic(&mut self.dst, &ss[..], Help,
|
||||
&format!("run `rustc --explain {}` to see a \
|
||||
detailed explanation", code), None)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()>
|
||||
{
|
||||
let lines = self.cm.span_to_lines(suggestion.msp.to_span_bounds()).unwrap();
|
||||
let primary_span = suggestion.msp.primary_span().unwrap();
|
||||
let lines = self.cm.span_to_lines(primary_span).unwrap();
|
||||
assert!(!lines.lines.is_empty());
|
||||
|
||||
let complete = suggestion.splice_lines(&self.cm);
|
||||
@ -251,325 +277,21 @@ impl EmitterWriter {
|
||||
lvl: Level)
|
||||
-> io::Result<()>
|
||||
{
|
||||
let lines = match self.cm.span_to_lines(msp.to_span_bounds()) {
|
||||
Ok(lines) => lines,
|
||||
Err(_) => {
|
||||
write!(&mut self.dst, "(internal compiler error: unprintable span)\n")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let fm = &*lines.file;
|
||||
if let None = fm.src {
|
||||
return Ok(());
|
||||
let mut snippet_data = SnippetData::new(self.cm.clone(),
|
||||
msp.primary_span());
|
||||
for span_label in msp.span_labels() {
|
||||
snippet_data.push(span_label.span,
|
||||
span_label.is_primary,
|
||||
span_label.label);
|
||||
}
|
||||
|
||||
let display_line_infos = &lines.lines[..];
|
||||
assert!(display_line_infos.len() > 0);
|
||||
|
||||
// Calculate the widest number to format evenly and fix #11715
|
||||
let digits = line_num_max_digits(display_line_infos.last().unwrap());
|
||||
let first_line_index = display_line_infos.first().unwrap().line_index;
|
||||
|
||||
let skip = fm.name.chars().count() + digits + 2;
|
||||
|
||||
let mut spans = msp.spans.iter().peekable();
|
||||
let mut lines = display_line_infos.iter();
|
||||
let mut prev_line_index = first_line_index.wrapping_sub(1);
|
||||
|
||||
// Display at most MAX_HIGHLIGHT_LINES lines.
|
||||
let mut remaining_err_lines = MAX_HIGHLIGHT_LINES;
|
||||
|
||||
// To emit a overflowed spans code-lines *AFTER* the rendered spans
|
||||
let mut overflowed_buf = String::new();
|
||||
let mut overflowed = false;
|
||||
|
||||
// FIXME (#8706)
|
||||
'l: loop {
|
||||
if remaining_err_lines <= 0 {
|
||||
break;
|
||||
let rendered_lines = snippet_data.render_lines();
|
||||
for rendered_line in &rendered_lines {
|
||||
for styled_string in &rendered_line.text {
|
||||
self.dst.apply_style(lvl, &rendered_line.kind, styled_string.style)?;
|
||||
write!(&mut self.dst, "{}", styled_string.text)?;
|
||||
self.dst.reset_attrs()?;
|
||||
}
|
||||
let line = match lines.next() {
|
||||
Some(l) => l,
|
||||
None => break,
|
||||
};
|
||||
|
||||
// Skip is the number of characters we need to skip because they are
|
||||
// part of the 'filename:line ' part of the code line.
|
||||
let mut s: String = ::std::iter::repeat(' ').take(skip).collect();
|
||||
let mut col = skip;
|
||||
let mut lastc = ' ';
|
||||
|
||||
let cur_line_str = fm.get_line(line.line_index).unwrap();
|
||||
let mut line_chars = cur_line_str.chars().enumerate().peekable();
|
||||
let mut line_spans = 0;
|
||||
|
||||
// Assemble spans for this line
|
||||
loop {
|
||||
// Peek here to preserve the span if it doesn't belong to this line
|
||||
let sp = match spans.peek() {
|
||||
Some(sp) => **sp,
|
||||
None => break,
|
||||
};
|
||||
let lo = self.cm.lookup_char_pos(sp.lo);
|
||||
let hi = self.cm.lookup_char_pos(sp.hi);
|
||||
let line_num = line.line_index + 1;
|
||||
|
||||
if !(lo.line <= line_num && hi.line >= line_num) {
|
||||
// This line is not contained in the span
|
||||
if overflowed {
|
||||
// Never elide the final line of an overflowed span
|
||||
prev_line_index = line.line_index - 1;
|
||||
overflowed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if line_spans == 0 {
|
||||
continue 'l;
|
||||
} else {
|
||||
// This line is finished, now render the spans we've assembled
|
||||
break;
|
||||
}
|
||||
}
|
||||
spans.next();
|
||||
line_spans += 1;
|
||||
|
||||
if lo.line != hi.line {
|
||||
// Assemble extra code lines to be emitted after this lines spans
|
||||
// (substract `2` because the first and last line are rendered normally)
|
||||
let max_lines = cmp::min(remaining_err_lines, MAX_SP_LINES) - 2;
|
||||
prev_line_index = line.line_index;
|
||||
let count = cmp::min((hi.line - lo.line - 1), max_lines);
|
||||
for _ in 0..count {
|
||||
let line = match lines.next() {
|
||||
Some(l) => l,
|
||||
None => break,
|
||||
};
|
||||
let line_str = fm.get_line(line.line_index).unwrap();
|
||||
overflowed_buf.push_str(&format!("{}:{:>width$} {}\n",
|
||||
fm.name,
|
||||
line.line_index + 1,
|
||||
line_str,
|
||||
width=digits));
|
||||
remaining_err_lines -= 1;
|
||||
prev_line_index += 1
|
||||
}
|
||||
// Remember that the span overflowed to ensure
|
||||
// that we emit its last line exactly once
|
||||
// (other spans may, or may not, start on it)
|
||||
overflowed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (pos, ch) in line_chars.by_ref() {
|
||||
lastc = ch;
|
||||
if pos >= lo.col.to_usize() { break; }
|
||||
// Whenever a tab occurs on the code line, we insert one on
|
||||
// the error-point-squiggly-line as well (instead of a space).
|
||||
// That way the squiggly line will usually appear in the correct
|
||||
// position.
|
||||
match ch {
|
||||
'\t' => {
|
||||
col += 8 - col%8;
|
||||
s.push('\t');
|
||||
},
|
||||
_ => {
|
||||
col += 1;
|
||||
s.push(' ');
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
s.push('^');
|
||||
let col_ptr = col;
|
||||
let count = match lastc {
|
||||
// Most terminals have a tab stop every eight columns by default
|
||||
'\t' => 8 - col%8,
|
||||
_ => 1,
|
||||
};
|
||||
col += count;
|
||||
s.extend(::std::iter::repeat('~').take(count));
|
||||
|
||||
let hi = self.cm.lookup_char_pos(sp.hi);
|
||||
if hi.col != lo.col {
|
||||
let mut chars = line_chars.by_ref();
|
||||
loop {
|
||||
// We peek here to preserve the value for the next span
|
||||
let (pos, ch) = match chars.peek() {
|
||||
Some(elem) => *elem,
|
||||
None => break,
|
||||
};
|
||||
if pos >= hi.col.to_usize() { break; }
|
||||
let count = match ch {
|
||||
'\t' => 8 - col%8,
|
||||
_ => 1,
|
||||
};
|
||||
col += count;
|
||||
s.extend(::std::iter::repeat('~').take(count));
|
||||
|
||||
chars.next();
|
||||
}
|
||||
}
|
||||
if (col - col_ptr) > 0 {
|
||||
// One extra squiggly is replaced by a "^"
|
||||
s.pop();
|
||||
}
|
||||
}
|
||||
|
||||
// If we elided something put an ellipsis.
|
||||
if prev_line_index != line.line_index.wrapping_sub(1) && !overflowed {
|
||||
write!(&mut self.dst, "{0:1$}...\n", "", skip)?;
|
||||
}
|
||||
|
||||
// Print offending code-line
|
||||
remaining_err_lines -= 1;
|
||||
write!(&mut self.dst, "{}:{:>width$} {}\n",
|
||||
fm.name,
|
||||
line.line_index + 1,
|
||||
cur_line_str,
|
||||
width=digits)?;
|
||||
|
||||
if s.len() > skip {
|
||||
// Render the spans we assembled previously (if any).
|
||||
println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()),
|
||||
"{}", s)?;
|
||||
}
|
||||
|
||||
if !overflowed_buf.is_empty() {
|
||||
// Print code-lines trailing the rendered spans (when a span overflows)
|
||||
write!(&mut self.dst, "{}", &overflowed_buf)?;
|
||||
overflowed_buf.clear();
|
||||
} else {
|
||||
prev_line_index = line.line_index;
|
||||
}
|
||||
}
|
||||
|
||||
// If we elided something, put an ellipsis.
|
||||
if lines.next().is_some() {
|
||||
write!(&mut self.dst, "{0:1$}...\n", "", skip)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Here are the differences between this and the normal `highlight_lines`:
|
||||
/// `end_highlight_lines` will always put arrow on the last byte of each
|
||||
/// span (instead of the first byte). Also, when a span is too long (more
|
||||
/// than 6 lines), `end_highlight_lines` will print the first line, then
|
||||
/// dot dot dot, then last line, whereas `highlight_lines` prints the first
|
||||
/// six lines.
|
||||
#[allow(deprecated)]
|
||||
fn end_highlight_lines(&mut self,
|
||||
msp: &MultiSpan,
|
||||
lvl: Level)
|
||||
-> io::Result<()> {
|
||||
let lines = match self.cm.span_to_lines(msp.to_span_bounds()) {
|
||||
Ok(lines) => lines,
|
||||
Err(_) => {
|
||||
write!(&mut self.dst, "(internal compiler error: unprintable span)\n")?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let fm = &*lines.file;
|
||||
if let None = fm.src {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let lines = &lines.lines[..];
|
||||
|
||||
// Calculate the widest number to format evenly
|
||||
let first_line = lines.first().unwrap();
|
||||
let last_line = lines.last().unwrap();
|
||||
let digits = line_num_max_digits(last_line);
|
||||
|
||||
let skip = fm.name.chars().count() + digits + 2;
|
||||
|
||||
let mut spans = msp.spans.iter().peekable();
|
||||
let mut lines = lines.iter();
|
||||
let mut prev_line_index = first_line.line_index.wrapping_sub(1);
|
||||
|
||||
// Display at most MAX_HIGHLIGHT_LINES lines.
|
||||
let mut remaining_err_lines = MAX_HIGHLIGHT_LINES;
|
||||
|
||||
'l: loop {
|
||||
if remaining_err_lines <= 0 {
|
||||
break;
|
||||
}
|
||||
let line = match lines.next() {
|
||||
Some(line) => line,
|
||||
None => break,
|
||||
};
|
||||
|
||||
// Skip is the number of characters we need to skip because they are
|
||||
// part of the 'filename:line ' part of the previous line.
|
||||
let mut s: String = ::std::iter::repeat(' ').take(skip).collect();
|
||||
|
||||
let line_str = fm.get_line(line.line_index).unwrap();
|
||||
let mut line_chars = line_str.chars().enumerate();
|
||||
let mut line_spans = 0;
|
||||
|
||||
loop {
|
||||
// Peek here to preserve the span if it doesn't belong to this line
|
||||
let sp = match spans.peek() {
|
||||
Some(sp) => **sp,
|
||||
None => break,
|
||||
};
|
||||
let lo = self.cm.lookup_char_pos(sp.lo);
|
||||
let hi = self.cm.lookup_char_pos(sp.hi);
|
||||
let elide_sp = (hi.line - lo.line) >= MAX_SP_LINES;
|
||||
|
||||
let line_num = line.line_index + 1;
|
||||
if !(lo.line <= line_num && hi.line >= line_num) {
|
||||
// This line is not contained in the span
|
||||
if line_spans == 0 {
|
||||
continue 'l;
|
||||
} else {
|
||||
// This line is finished, now render the spans we've assembled
|
||||
break
|
||||
}
|
||||
} else if hi.line > line_num {
|
||||
if elide_sp && lo.line < line_num {
|
||||
// This line is inbetween the first and last line of the span,
|
||||
// so we may want to elide it.
|
||||
continue 'l;
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
line_spans += 1;
|
||||
spans.next();
|
||||
|
||||
for (pos, ch) in line_chars.by_ref() {
|
||||
// Span seems to use half-opened interval, so subtract 1
|
||||
if pos >= hi.col.to_usize() - 1 { break; }
|
||||
// Whenever a tab occurs on the previous line, we insert one on
|
||||
// the error-point-squiggly-line as well (instead of a space).
|
||||
// That way the squiggly line will usually appear in the correct
|
||||
// position.
|
||||
match ch {
|
||||
'\t' => s.push('\t'),
|
||||
_ => s.push(' '),
|
||||
}
|
||||
}
|
||||
s.push('^');
|
||||
}
|
||||
|
||||
if prev_line_index != line.line_index.wrapping_sub(1) {
|
||||
// If we elided something, put an ellipsis.
|
||||
write!(&mut self.dst, "{0:1$}...\n", "", skip)?;
|
||||
}
|
||||
|
||||
// Print offending code-lines
|
||||
write!(&mut self.dst, "{}:{:>width$} {}\n", fm.name,
|
||||
line.line_index + 1, line_str, width=digits)?;
|
||||
remaining_err_lines -= 1;
|
||||
|
||||
if s.len() > skip {
|
||||
// Render the spans we assembled previously (if any)
|
||||
println_maybe_styled!(&mut self.dst, term::Attr::ForegroundColor(lvl.color()),
|
||||
"{}", s)?;
|
||||
}
|
||||
prev_line_index = line.line_index;
|
||||
write!(&mut self.dst, "\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -602,6 +324,7 @@ fn line_num_max_digits(line: &codemap::LineInfo) -> usize {
|
||||
digits
|
||||
}
|
||||
|
||||
|
||||
fn print_diagnostic(dst: &mut Destination,
|
||||
topic: &str,
|
||||
lvl: Level,
|
||||
@ -609,17 +332,22 @@ fn print_diagnostic(dst: &mut Destination,
|
||||
code: Option<&str>)
|
||||
-> io::Result<()> {
|
||||
if !topic.is_empty() {
|
||||
write!(dst, "{} ", topic)?;
|
||||
dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
|
||||
write!(dst, "{}: ", topic)?;
|
||||
dst.reset_attrs()?;
|
||||
}
|
||||
|
||||
print_maybe_styled!(dst, term::Attr::ForegroundColor(lvl.color()),
|
||||
"{}: ", lvl.to_string())?;
|
||||
print_maybe_styled!(dst, term::Attr::Bold, "{}", msg)?;
|
||||
|
||||
dst.start_attr(term::Attr::Bold)?;
|
||||
dst.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
|
||||
write!(dst, "{}", lvl.to_string())?;
|
||||
dst.reset_attrs()?;
|
||||
write!(dst, ": ")?;
|
||||
dst.start_attr(term::Attr::Bold)?;
|
||||
write!(dst, "{}", msg)?;
|
||||
if let Some(code) = code {
|
||||
let style = term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA);
|
||||
print_maybe_styled!(dst, style, " [{}]", code.clone())?;
|
||||
}
|
||||
dst.reset_attrs()?;
|
||||
write!(dst, "\n")?;
|
||||
Ok(())
|
||||
}
|
||||
@ -660,6 +388,52 @@ impl Destination {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_style(&mut self,
|
||||
lvl: Level,
|
||||
_kind: &RenderedLineKind,
|
||||
style: Style)
|
||||
-> io::Result<()> {
|
||||
match style {
|
||||
Style::FileNameStyle => {
|
||||
}
|
||||
Style::LineAndColumn => {
|
||||
}
|
||||
Style::LineNumber => {
|
||||
self.start_attr(term::Attr::Bold)?;
|
||||
self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
|
||||
}
|
||||
Style::Quotation => {
|
||||
}
|
||||
Style::UnderlinePrimary | Style::LabelPrimary => {
|
||||
self.start_attr(term::Attr::Bold)?;
|
||||
self.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
|
||||
}
|
||||
Style::UnderlineSecondary | Style::LabelSecondary => {
|
||||
self.start_attr(term::Attr::Bold)?;
|
||||
self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?;
|
||||
}
|
||||
Style::NoStyle => {
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> {
|
||||
match *self {
|
||||
Terminal(ref mut t) => { t.attr(attr)?; }
|
||||
Raw(_) => { }
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reset_attrs(&mut self) -> io::Result<()> {
|
||||
match *self {
|
||||
Terminal(ref mut t) => { t.reset()?; }
|
||||
Raw(_) => { }
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_maybe_styled(&mut self,
|
||||
args: fmt::Arguments,
|
||||
color: term::Attr,
|
||||
@ -741,7 +515,7 @@ mod test {
|
||||
/// that this can span lines and so on.
|
||||
fn span_from_selection(input: &str, selection: &str) -> Span {
|
||||
assert_eq!(input.len(), selection.len());
|
||||
let left_index = selection.find('^').unwrap() as u32;
|
||||
let left_index = selection.find('~').unwrap() as u32;
|
||||
let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index);
|
||||
Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION }
|
||||
}
|
||||
@ -777,12 +551,15 @@ mod test {
|
||||
let vec = data.lock().unwrap().clone();
|
||||
let vec: &[u8] = &vec;
|
||||
let str = from_utf8(vec).unwrap();
|
||||
println!("{}", str);
|
||||
assert_eq!(str, "dummy.txt: 8 line8\n\
|
||||
dummy.txt: 9 line9\n\
|
||||
dummy.txt:10 line10\n\
|
||||
dummy.txt:11 e-lä-vän\n\
|
||||
dummy.txt:12 tolv\n");
|
||||
println!("r#\"\n{}\"#", str);
|
||||
assert_eq!(str, &r#"
|
||||
--> dummy.txt:8:1
|
||||
8 |> line8
|
||||
|> ^^^^^^^^^^^^^
|
||||
...
|
||||
11 |> e-lä-vän
|
||||
|> ^^^^^^^^^^^^^^^^
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -790,7 +567,7 @@ mod test {
|
||||
// Test that a `MultiSpan` containing a single span splices a substition correctly
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
|
||||
let selection = " \n ^~\n~~~\n~~~~~ \n \n";
|
||||
let selection = " \n ~~\n~~~\n~~~~~ \n \n";
|
||||
cm.new_filemap_and_lines("blork.rs", inputtext);
|
||||
let sp = span_from_selection(inputtext, selection);
|
||||
let msp: MultiSpan = sp.into();
|
||||
@ -808,51 +585,25 @@ mod test {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_span_splice() {
|
||||
// Test that a `MultiSpan` containing multiple spans splices substitions on
|
||||
// several lines correctly
|
||||
fn test_multi_span_splice() {
|
||||
// Test that a `MultiSpan` containing multiple spans splices a substition correctly
|
||||
let cm = CodeMap::new();
|
||||
let inp = "aaaaabbbbBB\nZZ\nZZ\nCCCDDDDDdddddeee";
|
||||
let sp1 = " ^~~~~~\n \n \n ";
|
||||
let sp2 = " \n \n \n^~~~~~ ";
|
||||
let sp3 = " \n \n \n ^~~ ";
|
||||
let sp4 = " \n \n \n ^~~~ ";
|
||||
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
|
||||
let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order
|
||||
let selection2 = " \n ~~\n~~~\n~~~~~ \n \n";
|
||||
cm.new_filemap_and_lines("blork.rs", inputtext);
|
||||
let sp1 = span_from_selection(inputtext, selection1);
|
||||
let sp2 = span_from_selection(inputtext, selection2);
|
||||
let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]);
|
||||
|
||||
let span_eq = |sp, eq| assert_eq!(&cm.span_to_snippet(sp).unwrap(), eq);
|
||||
|
||||
cm.new_filemap_and_lines("blork.rs", inp);
|
||||
let sp1 = span_from_selection(inp, sp1);
|
||||
let sp2 = span_from_selection(inp, sp2);
|
||||
let sp3 = span_from_selection(inp, sp3);
|
||||
let sp4 = span_from_selection(inp, sp4);
|
||||
span_eq(sp1, "bbbbBB");
|
||||
span_eq(sp2, "CCCDDD");
|
||||
span_eq(sp3, "ddd");
|
||||
span_eq(sp4, "ddee");
|
||||
|
||||
let substitutes: Vec<String> = ["1", "2", "3", "4"].iter().map(|x|x.to_string()).collect();
|
||||
let expected = "aaaaa1\nZZ\nZZ\n2DD34e";
|
||||
|
||||
let test = |msp| {
|
||||
let suggest = CodeSuggestion {
|
||||
msp: msp,
|
||||
substitutes: substitutes.clone(),
|
||||
};
|
||||
let actual = suggest.splice_lines(&cm);
|
||||
assert_eq!(actual, expected);
|
||||
let expected = "bbbbZZZZZZddddd\neXYZe";
|
||||
let suggest = CodeSuggestion {
|
||||
msp: msp,
|
||||
substitutes: vec!["ZZZZZZ".to_owned(),
|
||||
"XYZ".to_owned()]
|
||||
};
|
||||
test(MultiSpan { spans: vec![sp1, sp2, sp3, sp4] });
|
||||
|
||||
// Test ordering and merging by `MultiSpan::push`
|
||||
let mut msp = MultiSpan::new();
|
||||
msp.push_merge(sp2);
|
||||
msp.push_merge(sp1);
|
||||
assert_eq!(&msp.spans, &[sp1, sp2]);
|
||||
msp.push_merge(sp4);
|
||||
assert_eq!(&msp.spans, &[sp1, sp2, sp4]);
|
||||
msp.push_merge(sp3);
|
||||
assert_eq!(&msp.spans, &[sp1, sp2, sp3, sp4]);
|
||||
test(msp);
|
||||
assert_eq!(suggest.splice_lines(&cm), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -862,17 +613,17 @@ mod test {
|
||||
let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
|
||||
|
||||
let inp = "_____aaaaaa____bbbbbb__cccccdd_";
|
||||
let sp1 = " ^~~~~~ ";
|
||||
let sp2 = " ^~~~~~ ";
|
||||
let sp3 = " ^~~~~ ";
|
||||
let sp4 = " ^~~~ ";
|
||||
let sp34 = " ^~~~~~~ ";
|
||||
let sp4_end = " ^~ ";
|
||||
let sp1 = " ~~~~~~ ";
|
||||
let sp2 = " ~~~~~~ ";
|
||||
let sp3 = " ~~~~~ ";
|
||||
let sp4 = " ~~~~ ";
|
||||
let sp34 = " ~~~~~~~ ";
|
||||
|
||||
let expect_start = "dummy.txt:1 _____aaaaaa____bbbbbb__cccccdd_\n\
|
||||
\x20 ^~~~~~ ^~~~~~ ^~~~~~~\n";
|
||||
let expect_end = "dummy.txt:1 _____aaaaaa____bbbbbb__cccccdd_\n\
|
||||
\x20 ^ ^ ^ ^\n";
|
||||
let expect_start = &r#"
|
||||
--> dummy.txt:1:6
|
||||
1 |> _____aaaaaa____bbbbbb__cccccdd_
|
||||
|> ^^^^^^ ^^^^^^ ^^^^^^^
|
||||
"#[1..];
|
||||
|
||||
let span = |sp, expected| {
|
||||
let sp = span_from_selection(inp, sp);
|
||||
@ -885,7 +636,6 @@ mod test {
|
||||
let sp3 = span(sp3, "ccccc");
|
||||
let sp4 = span(sp4, "ccdd");
|
||||
let sp34 = span(sp34, "cccccdd");
|
||||
let sp4_end = span(sp4_end, "dd");
|
||||
|
||||
let spans = vec![sp1, sp2, sp3, sp4];
|
||||
|
||||
@ -894,26 +644,17 @@ mod test {
|
||||
highlight();
|
||||
let vec = data.lock().unwrap().clone();
|
||||
let actual = from_utf8(&vec[..]).unwrap();
|
||||
println!("actual=\n{}", actual);
|
||||
assert_eq!(actual, expected);
|
||||
};
|
||||
|
||||
let msp = MultiSpan { spans: vec![sp1, sp2, sp34] };
|
||||
let msp_end = MultiSpan { spans: vec![sp1, sp2, sp3, sp4_end] };
|
||||
let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]);
|
||||
test(expect_start, &mut || {
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
test(expect_end, &mut || {
|
||||
diag.end_highlight_lines(&msp_end, Level::Error).unwrap();
|
||||
});
|
||||
test(expect_start, &mut || {
|
||||
for msp in cm.group_spans(spans.clone()) {
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
}
|
||||
});
|
||||
test(expect_end, &mut || {
|
||||
for msp in cm.end_group_spans(spans.clone()) {
|
||||
diag.end_highlight_lines(&msp, Level::Error).unwrap();
|
||||
}
|
||||
let msp = MultiSpan::from_spans(spans.clone());
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
@ -950,75 +691,31 @@ mod test {
|
||||
let sp4 = span(10, 10, (2, 3));
|
||||
let sp5 = span(10, 10, (4, 6));
|
||||
|
||||
let expect0 = "dummy.txt: 5 ccccc\n\
|
||||
dummy.txt: 6 xxxxx\n\
|
||||
dummy.txt: 7 yyyyy\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt: 9 ddd__eee_\n\
|
||||
\x20 ^~~ ^~~\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt:11 __f_gg\n\
|
||||
\x20 ^ ^~\n";
|
||||
let expect0 = &r#"
|
||||
--> dummy.txt:5:1
|
||||
5 |> ccccc
|
||||
|> ^^^^^
|
||||
...
|
||||
8 |> _____
|
||||
9 |> ddd__eee_
|
||||
|> ^^^ ^^^
|
||||
10 |> elided
|
||||
11 |> __f_gg
|
||||
|> ^ ^^
|
||||
"#[1..];
|
||||
|
||||
let expect = "dummy.txt: 1 aaaaa\n\
|
||||
dummy.txt: 2 aaaaa\n\
|
||||
dummy.txt: 3 aaaaa\n\
|
||||
dummy.txt: 4 bbbbb\n\
|
||||
dummy.txt: 5 ccccc\n\
|
||||
dummy.txt: 6 xxxxx\n\
|
||||
\x20 ...\n";
|
||||
|
||||
let expect_g1 = "dummy.txt:1 aaaaa\n\
|
||||
dummy.txt:2 aaaaa\n\
|
||||
dummy.txt:3 aaaaa\n\
|
||||
dummy.txt:4 bbbbb\n\
|
||||
dummy.txt:5 ccccc\n\
|
||||
dummy.txt:6 xxxxx\n\
|
||||
\x20 ...\n";
|
||||
|
||||
let expect2 = "dummy.txt: 9 ddd__eee_\n\
|
||||
\x20 ^~~ ^~~\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt:11 __f_gg\n\
|
||||
\x20 ^ ^~\n";
|
||||
|
||||
|
||||
let expect_end = "dummy.txt: 1 aaaaa\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt: 7 yyyyy\n\
|
||||
\x20 ^\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt: 9 ddd__eee_\n\
|
||||
\x20 ^ ^\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt:11 __f_gg\n\
|
||||
\x20 ^ ^\n";
|
||||
|
||||
let expect0_end = "dummy.txt: 5 ccccc\n\
|
||||
dummy.txt: 6 xxxxx\n\
|
||||
dummy.txt: 7 yyyyy\n\
|
||||
\x20 ^\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt: 9 ddd__eee_\n\
|
||||
\x20 ^ ^\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt:11 __f_gg\n\
|
||||
\x20 ^ ^\n";
|
||||
|
||||
let expect_end_g1 = "dummy.txt:1 aaaaa\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt:7 yyyyy\n\
|
||||
\x20 ^\n";
|
||||
|
||||
let expect2_end = "dummy.txt: 9 ddd__eee_\n\
|
||||
\x20 ^ ^\n\
|
||||
\x20 ...\n\
|
||||
dummy.txt:11 __f_gg\n\
|
||||
\x20 ^ ^\n";
|
||||
|
||||
let expect_groups = [expect2, expect_g1];
|
||||
let expect_end_groups = [expect2_end, expect_end_g1];
|
||||
let spans = vec![sp3, sp1, sp4, sp2, sp5];
|
||||
let expect = &r#"
|
||||
--> dummy.txt:1:1
|
||||
1 |> aaaaa
|
||||
|> ^^^^^
|
||||
...
|
||||
8 |> _____
|
||||
9 |> ddd__eee_
|
||||
|> ^^^ ^^^
|
||||
10 |> elided
|
||||
11 |> __f_gg
|
||||
|> ^ ^^
|
||||
"#[1..];
|
||||
|
||||
macro_rules! test {
|
||||
($expected: expr, $highlight: expr) => ({
|
||||
@ -1034,37 +731,14 @@ mod test {
|
||||
});
|
||||
}
|
||||
|
||||
let msp0 = MultiSpan { spans: vec![sp0, sp2, sp3, sp4, sp5] };
|
||||
let msp = MultiSpan { spans: vec![sp1, sp2, sp3, sp4, sp5] };
|
||||
let msp2 = MultiSpan { spans: vec![sp2, sp3, sp4, sp5] };
|
||||
let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]);
|
||||
let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]);
|
||||
|
||||
test!(expect0, || {
|
||||
diag.highlight_lines(&msp0, Level::Error).unwrap();
|
||||
});
|
||||
test!(expect0_end, || {
|
||||
diag.end_highlight_lines(&msp0, Level::Error).unwrap();
|
||||
});
|
||||
test!(expect, || {
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
test!(expect_end, || {
|
||||
diag.end_highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
test!(expect2, || {
|
||||
diag.highlight_lines(&msp2, Level::Error).unwrap();
|
||||
});
|
||||
test!(expect2_end, || {
|
||||
diag.end_highlight_lines(&msp2, Level::Error).unwrap();
|
||||
});
|
||||
for (msp, expect) in cm.group_spans(spans.clone()).iter().zip(expect_groups.iter()) {
|
||||
test!(expect, || {
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
}
|
||||
for (msp, expect) in cm.group_spans(spans.clone()).iter().zip(expect_end_groups.iter()) {
|
||||
test!(expect, || {
|
||||
diag.end_highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ pub use errors::emitter::ColorConfig;
|
||||
use self::Level::*;
|
||||
use self::RenderSpan::*;
|
||||
|
||||
use codemap::{self, CodeMap, MultiSpan};
|
||||
use codemap::{self, CodeMap, MultiSpan, NO_EXPANSION, Span};
|
||||
use diagnostics;
|
||||
use errors::emitter::{Emitter, EmitterWriter};
|
||||
|
||||
@ -24,6 +24,7 @@ use term;
|
||||
|
||||
pub mod emitter;
|
||||
pub mod json;
|
||||
pub mod snippet;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum RenderSpan {
|
||||
@ -32,13 +33,6 @@ pub enum RenderSpan {
|
||||
/// the source code covered by the span.
|
||||
FullSpan(MultiSpan),
|
||||
|
||||
/// Similar to a FullSpan, but the cited position is the end of
|
||||
/// the span, instead of the start. Used, at least, for telling
|
||||
/// compiletest/runtest to look at the last line of the span
|
||||
/// (since `end_highlight_lines` displays an arrow to the end
|
||||
/// of the span).
|
||||
EndSpan(MultiSpan),
|
||||
|
||||
/// A suggestion renders with both with an initial line for the
|
||||
/// message, prefixed by file:linenum, followed by a summary
|
||||
/// of hypothetical source code, where each `String` is spliced
|
||||
@ -61,7 +55,6 @@ impl RenderSpan {
|
||||
match *self {
|
||||
FullSpan(ref msp) |
|
||||
Suggestion(CodeSuggestion { ref msp, .. }) |
|
||||
EndSpan(ref msp) |
|
||||
FileLine(ref msp) =>
|
||||
msp
|
||||
}
|
||||
@ -88,12 +81,24 @@ impl CodeSuggestion {
|
||||
}
|
||||
}
|
||||
}
|
||||
let bounds = self.msp.to_span_bounds();
|
||||
let lines = cm.span_to_lines(bounds).unwrap();
|
||||
assert!(!lines.lines.is_empty());
|
||||
|
||||
// This isn't strictly necessary, but would in all likelyhood be an error
|
||||
assert_eq!(self.msp.spans.len(), self.substitutes.len());
|
||||
let mut primary_spans = self.msp.primary_spans().to_owned();
|
||||
|
||||
assert_eq!(primary_spans.len(), self.substitutes.len());
|
||||
if primary_spans.is_empty() {
|
||||
return format!("");
|
||||
}
|
||||
|
||||
// Assumption: all spans are in the same file, and all spans
|
||||
// are disjoint. Sort in ascending order.
|
||||
primary_spans.sort_by_key(|sp| sp.lo);
|
||||
|
||||
// Find the bounding span.
|
||||
let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap();
|
||||
let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap();
|
||||
let bounding_span = Span { lo: lo, hi: hi, expn_id: NO_EXPANSION };
|
||||
let lines = cm.span_to_lines(bounding_span).unwrap();
|
||||
assert!(!lines.lines.is_empty());
|
||||
|
||||
// To build up the result, we do this for each span:
|
||||
// - push the line segment trailing the previous span
|
||||
@ -105,13 +110,13 @@ impl CodeSuggestion {
|
||||
//
|
||||
// Finally push the trailing line segment of the last span
|
||||
let fm = &lines.file;
|
||||
let mut prev_hi = cm.lookup_char_pos(bounds.lo);
|
||||
let mut prev_hi = cm.lookup_char_pos(bounding_span.lo);
|
||||
prev_hi.col = CharPos::from_usize(0);
|
||||
|
||||
let mut prev_line = fm.get_line(lines.lines[0].line_index);
|
||||
let mut buf = String::new();
|
||||
|
||||
for (sp, substitute) in self.msp.spans.iter().zip(self.substitutes.iter()) {
|
||||
for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
|
||||
let cur_lo = cm.lookup_char_pos(sp.lo);
|
||||
if prev_hi.line == cur_lo.line {
|
||||
push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
|
||||
@ -183,7 +188,7 @@ pub struct DiagnosticBuilder<'a> {
|
||||
level: Level,
|
||||
message: String,
|
||||
code: Option<String>,
|
||||
span: Option<MultiSpan>,
|
||||
span: MultiSpan,
|
||||
children: Vec<SubDiagnostic>,
|
||||
}
|
||||
|
||||
@ -192,7 +197,7 @@ pub struct DiagnosticBuilder<'a> {
|
||||
struct SubDiagnostic {
|
||||
level: Level,
|
||||
message: String,
|
||||
span: Option<MultiSpan>,
|
||||
span: MultiSpan,
|
||||
render_span: Option<RenderSpan>,
|
||||
}
|
||||
|
||||
@ -228,37 +233,61 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||
self.level == Level::Fatal
|
||||
}
|
||||
|
||||
pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, None, None);
|
||||
/// Add a span/label to be included in the resulting snippet.
|
||||
/// This is pushed onto the `MultiSpan` that was created when the
|
||||
/// diagnostic was first built. If you don't call this function at
|
||||
/// all, and you just supplied a `Span` to create the diagnostic,
|
||||
/// then the snippet will just include that `Span`, which is
|
||||
/// called the primary span.
|
||||
pub fn span_label(mut self, span: Span, label: &fmt::Display)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.span.push_span_label(span, format!("{}", label));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn note_expected_found(mut self,
|
||||
label: &fmt::Display,
|
||||
expected: &fmt::Display,
|
||||
found: &fmt::Display)
|
||||
-> DiagnosticBuilder<'a>
|
||||
{
|
||||
// For now, just attach these as notes
|
||||
self.note(&format!("expected {} `{}`", label, expected));
|
||||
self.note(&format!(" found {} `{}`", label, found));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
pub fn span_note<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, Some(sp.into()), None);
|
||||
self.sub(Level::Note, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Warning, msg, None, None);
|
||||
self.sub(Level::Warning, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
pub fn span_warn<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Warning, msg, Some(sp.into()), None);
|
||||
self.sub(Level::Warning, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Help, msg, None, None);
|
||||
self.sub(Level::Help, msg, MultiSpan::new(), None);
|
||||
self
|
||||
}
|
||||
pub fn span_help<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Help, msg, Some(sp.into()), None);
|
||||
self.sub(Level::Help, msg, sp.into(), None);
|
||||
self
|
||||
}
|
||||
/// Prints out a message with a suggested edit of the code.
|
||||
@ -269,43 +298,15 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||
msg: &str,
|
||||
suggestion: String)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Help, msg, None, Some(Suggestion(CodeSuggestion {
|
||||
self.sub(Level::Help, msg, MultiSpan::new(), Some(Suggestion(CodeSuggestion {
|
||||
msp: sp.into(),
|
||||
substitutes: vec![suggestion],
|
||||
})));
|
||||
self
|
||||
}
|
||||
pub fn span_end_note<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, None, Some(EndSpan(sp.into())));
|
||||
self
|
||||
}
|
||||
pub fn fileline_warn<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Warning, msg, None, Some(FileLine(sp.into())));
|
||||
self
|
||||
}
|
||||
pub fn fileline_note<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Note, msg, None, Some(FileLine(sp.into())));
|
||||
self
|
||||
}
|
||||
pub fn fileline_help<S: Into<MultiSpan>>(&mut self,
|
||||
sp: S,
|
||||
msg: &str)
|
||||
-> &mut DiagnosticBuilder<'a> {
|
||||
self.sub(Level::Help, msg, None, Some(FileLine(sp.into())));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
|
||||
self.span = Some(sp.into());
|
||||
pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
|
||||
self.span = sp.into();
|
||||
self
|
||||
}
|
||||
|
||||
@ -324,7 +325,7 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||
level: level,
|
||||
message: message.to_owned(),
|
||||
code: None,
|
||||
span: None,
|
||||
span: MultiSpan::new(),
|
||||
children: vec![],
|
||||
}
|
||||
}
|
||||
@ -334,7 +335,7 @@ impl<'a> DiagnosticBuilder<'a> {
|
||||
fn sub(&mut self,
|
||||
level: Level,
|
||||
message: &str,
|
||||
span: Option<MultiSpan>,
|
||||
span: MultiSpan,
|
||||
render_span: Option<RenderSpan>) {
|
||||
let sub = SubDiagnostic {
|
||||
level: level,
|
||||
@ -357,7 +358,10 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
|
||||
impl<'a> Drop for DiagnosticBuilder<'a> {
|
||||
fn drop(&mut self) {
|
||||
if !self.cancelled() {
|
||||
self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug);
|
||||
self.emitter.borrow_mut().emit(&MultiSpan::new(),
|
||||
"Error constructed but not emitted",
|
||||
None,
|
||||
Bug);
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
@ -412,7 +416,7 @@ impl Handler {
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
|
||||
result.span(sp);
|
||||
result.set_span(sp);
|
||||
if !self.can_emit_warnings {
|
||||
result.cancel();
|
||||
}
|
||||
@ -424,7 +428,7 @@ impl Handler {
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
|
||||
result.span(sp);
|
||||
result.set_span(sp);
|
||||
result.code(code.to_owned());
|
||||
if !self.can_emit_warnings {
|
||||
result.cancel();
|
||||
@ -444,7 +448,7 @@ impl Handler {
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
|
||||
result.span(sp);
|
||||
result.set_span(sp);
|
||||
result
|
||||
}
|
||||
pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self,
|
||||
@ -454,7 +458,7 @@ impl Handler {
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
|
||||
result.span(sp);
|
||||
result.set_span(sp);
|
||||
result.code(code.to_owned());
|
||||
result
|
||||
}
|
||||
@ -468,7 +472,7 @@ impl Handler {
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
|
||||
result.span(sp);
|
||||
result.set_span(sp);
|
||||
result
|
||||
}
|
||||
pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self,
|
||||
@ -478,7 +482,7 @@ impl Handler {
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
|
||||
result.span(sp);
|
||||
result.set_span(sp);
|
||||
result.code(code.to_owned());
|
||||
result
|
||||
}
|
||||
@ -499,7 +503,7 @@ impl Handler {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
self.emit(Some(&sp.into()), msg, Fatal);
|
||||
self.emit(&sp.into(), msg, Fatal);
|
||||
self.bump_err_count();
|
||||
return FatalError;
|
||||
}
|
||||
@ -508,7 +512,7 @@ impl Handler {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
self.emit_with_code(Some(&sp.into()), msg, code, Fatal);
|
||||
self.emit_with_code(&sp.into(), msg, code, Fatal);
|
||||
self.bump_err_count();
|
||||
return FatalError;
|
||||
}
|
||||
@ -516,24 +520,24 @@ impl Handler {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
self.emit(Some(&sp.into()), msg, Error);
|
||||
self.emit(&sp.into(), msg, Error);
|
||||
self.bump_err_count();
|
||||
}
|
||||
pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
|
||||
if self.treat_err_as_bug {
|
||||
self.span_bug(sp, msg);
|
||||
}
|
||||
self.emit_with_code(Some(&sp.into()), msg, code, Error);
|
||||
self.emit_with_code(&sp.into(), msg, code, Error);
|
||||
self.bump_err_count();
|
||||
}
|
||||
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.emit(Some(&sp.into()), msg, Warning);
|
||||
self.emit(&sp.into(), msg, Warning);
|
||||
}
|
||||
pub fn span_warn_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
|
||||
self.emit_with_code(Some(&sp.into()), msg, code, Warning);
|
||||
self.emit_with_code(&sp.into(), msg, code, Warning);
|
||||
}
|
||||
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
|
||||
self.emit(Some(&sp.into()), msg, Bug);
|
||||
self.emit(&sp.into(), msg, Bug);
|
||||
panic!(ExplicitBug);
|
||||
}
|
||||
pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
@ -541,11 +545,11 @@ impl Handler {
|
||||
*delayed = Some((sp.into(), msg.to_string()));
|
||||
}
|
||||
pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.emit(Some(&sp.into()), msg, Bug);
|
||||
self.emit(&sp.into(), msg, Bug);
|
||||
self.bump_err_count();
|
||||
}
|
||||
pub fn span_note_without_error<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
|
||||
self.emit.borrow_mut().emit(Some(&sp.into()), msg, None, Note);
|
||||
self.emit.borrow_mut().emit(&sp.into(), msg, None, Note);
|
||||
}
|
||||
pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
|
||||
self.span_bug(sp, &format!("unimplemented {}", msg));
|
||||
@ -554,7 +558,7 @@ impl Handler {
|
||||
if self.treat_err_as_bug {
|
||||
self.bug(msg);
|
||||
}
|
||||
self.emit.borrow_mut().emit(None, msg, None, Fatal);
|
||||
self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Fatal);
|
||||
self.bump_err_count();
|
||||
FatalError
|
||||
}
|
||||
@ -562,17 +566,17 @@ impl Handler {
|
||||
if self.treat_err_as_bug {
|
||||
self.bug(msg);
|
||||
}
|
||||
self.emit.borrow_mut().emit(None, msg, None, Error);
|
||||
self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Error);
|
||||
self.bump_err_count();
|
||||
}
|
||||
pub fn warn(&self, msg: &str) {
|
||||
self.emit.borrow_mut().emit(None, msg, None, Warning);
|
||||
self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Warning);
|
||||
}
|
||||
pub fn note_without_error(&self, msg: &str) {
|
||||
self.emit.borrow_mut().emit(None, msg, None, Note);
|
||||
self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Note);
|
||||
}
|
||||
pub fn bug(&self, msg: &str) -> ! {
|
||||
self.emit.borrow_mut().emit(None, msg, None, Bug);
|
||||
self.emit.borrow_mut().emit(&MultiSpan::new(), msg, None, Bug);
|
||||
panic!(ExplicitBug);
|
||||
}
|
||||
pub fn unimpl(&self, msg: &str) -> ! {
|
||||
@ -614,25 +618,20 @@ impl Handler {
|
||||
panic!(self.fatal(&s));
|
||||
}
|
||||
pub fn emit(&self,
|
||||
msp: Option<&MultiSpan>,
|
||||
msp: &MultiSpan,
|
||||
msg: &str,
|
||||
lvl: Level) {
|
||||
if lvl == Warning && !self.can_emit_warnings { return }
|
||||
self.emit.borrow_mut().emit(msp, msg, None, lvl);
|
||||
self.emit.borrow_mut().emit(&msp, msg, None, lvl);
|
||||
if !self.continue_after_error.get() { self.abort_if_errors(); }
|
||||
}
|
||||
pub fn emit_with_code(&self,
|
||||
msp: Option<&MultiSpan>,
|
||||
msp: &MultiSpan,
|
||||
msg: &str,
|
||||
code: &str,
|
||||
lvl: Level) {
|
||||
if lvl == Warning && !self.can_emit_warnings { return }
|
||||
self.emit.borrow_mut().emit(msp, msg, Some(code), lvl);
|
||||
if !self.continue_after_error.get() { self.abort_if_errors(); }
|
||||
}
|
||||
pub fn custom_emit(&self, rsp: RenderSpan, msg: &str, lvl: Level) {
|
||||
if lvl == Warning && !self.can_emit_warnings { return }
|
||||
self.emit.borrow_mut().custom_emit(&rsp, msg, lvl);
|
||||
self.emit.borrow_mut().emit(&msp, msg, Some(code), lvl);
|
||||
if !self.continue_after_error.get() { self.abort_if_errors(); }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user