diff options
| author | bors <bors@rust-lang.org> | 2016-01-28 22:13:25 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-01-28 22:13:25 +0000 |
| commit | 142214d1f2232a4e88ff7bd99951b01f36052c61 (patch) | |
| tree | 1d6bb4858399c46d39d9f85076cef439fb899f94 /src/libsyntax/errors/mod.rs | |
| parent | 552bf75e7d689c42febc7798d31ae58d614418f9 (diff) | |
| parent | 727f959095023d9fa749acbba49a4a904c57356b (diff) | |
| download | rust-142214d1f2232a4e88ff7bd99951b01f36052c61.tar.gz rust-142214d1f2232a4e88ff7bd99951b01f36052c61.zip | |
Auto merge of #30411 - mitaa:multispan, r=nrc
This allows to render multiple spans on one line, or to splice multiple replacements into a code suggestion. fixes #28124
Diffstat (limited to 'src/libsyntax/errors/mod.rs')
| -rw-r--r-- | src/libsyntax/errors/mod.rs | 325 |
1 files changed, 201 insertions, 124 deletions
diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index a7a4ddc3b2a..9e1cb60f54f 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -13,7 +13,7 @@ pub use errors::emitter::ColorConfig; use self::Level::*; use self::RenderSpan::*; -use codemap::{self, Span}; +use codemap::{self, CodeMap, MultiSpan}; use diagnostics; use errors::emitter::{Emitter, EmitterWriter}; @@ -31,35 +31,112 @@ pub enum RenderSpan { /// A FullSpan renders with both with an initial line for the /// message, prefixed by file:linenum, followed by a summary of /// the source code covered by the span. - FullSpan(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(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 the `String` is spliced - /// into the lines in place of the code covered by the span. - Suggestion(Span, String), + /// of hypothetical source code, where each `String` is spliced + /// into the lines in place of the code covered by each span. + Suggestion(CodeSuggestion), /// A FileLine renders with just a line for the message prefixed /// by file:linenum. - FileLine(Span), + FileLine(MultiSpan), +} + +#[derive(Clone)] +pub struct CodeSuggestion { + msp: MultiSpan, + substitutes: Vec<String>, } impl RenderSpan { - fn span(&self) -> Span { + fn span(&self) -> &MultiSpan { match *self { - FullSpan(s) | - Suggestion(s, _) | - EndSpan(s) | - FileLine(s) => - s + FullSpan(ref msp) | + Suggestion(CodeSuggestion { ref msp, .. }) | + EndSpan(ref msp) | + FileLine(ref msp) => + msp + } + } +} + +impl CodeSuggestion { + /// Returns the assembled code suggestion. + pub fn splice_lines(&self, cm: &CodeMap) -> String { + use codemap::{CharPos, Loc, Pos}; + + fn push_trailing(buf: &mut String, line_opt: Option<&str>, + lo: &Loc, hi_opt: Option<&Loc>) { + let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi|hi.col.to_usize())); + if let Some(line) = line_opt { + if line.len() > lo { + buf.push_str(match hi_opt { + Some(hi) => &line[lo..hi], + None => &line[lo..], + }); + } + if let None = hi_opt { + buf.push('\n'); + } + } + } + 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()); + + // To build up the result, we do this for each span: + // - push the line segment trailing the previous span + // (at the beginning a "phantom" span pointing at the start of the line) + // - push lines between the previous and current span (if any) + // - if the previous and current span are not on the same line + // push the line segment leading up to the current span + // - splice in the span substitution + // + // Finally push the trailing line segment of the last span + let fm = &lines.file; + let mut prev_hi = cm.lookup_char_pos(bounds.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()) { + 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)); + } else { + push_trailing(&mut buf, prev_line, &prev_hi, None); + // push lines between the previous and current span (if any) + for idx in prev_hi.line..(cur_lo.line - 1) { + if let Some(line) = fm.get_line(idx) { + buf.push_str(line); + buf.push('\n'); + } + } + if let Some(cur_line) = fm.get_line(cur_lo.line - 1) { + buf.push_str(&cur_line[.. cur_lo.col.to_usize()]); + } + } + buf.push_str(substitute); + prev_hi = cm.lookup_char_pos(sp.hi); + prev_line = fm.get_line(prev_hi.line - 1); } + push_trailing(&mut buf, prev_line, &prev_hi, None); + // remove trailing newline + buf.pop(); + buf } } @@ -106,7 +183,7 @@ pub struct DiagnosticBuilder<'a> { level: Level, message: String, code: Option<String>, - span: Option<Span>, + span: Option<MultiSpan>, children: Vec<SubDiagnostic>, } @@ -114,7 +191,7 @@ pub struct DiagnosticBuilder<'a> { struct SubDiagnostic { level: Level, message: String, - span: Option<Span>, + span: Option<MultiSpan>, render_span: Option<RenderSpan>, } @@ -150,81 +227,84 @@ impl<'a> DiagnosticBuilder<'a> { self.level == Level::Fatal } - pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { + pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { self.sub(Level::Note, msg, None, None); self } - pub fn span_note(&mut self , - sp: Span, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, Some(sp), None); + 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 } - pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { + pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { self.sub(Level::Warning, msg, None, None); self } - pub fn span_warn(&mut self, - sp: Span, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, Some(sp), None); + 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 } - pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { + pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { self.sub(Level::Help, msg, None, None); self } - pub fn span_help(&mut self , - sp: Span, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, Some(sp), None); + 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 } /// Prints out a message with a suggested edit of the code. /// /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion(&mut self , - sp: Span, - msg: &str, - suggestion: String) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, Some(sp), Some(Suggestion(sp, suggestion))); + pub fn span_suggestion<S: Into<MultiSpan>>(&mut self, + sp: S, + msg: &str, + suggestion: String) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, None, Some(Suggestion(CodeSuggestion { + msp: sp.into(), + substitutes: vec![suggestion], + }))); self } - pub fn span_end_note(&mut self , - sp: Span, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, Some(sp), Some(EndSpan(sp))); + 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(&mut self , - sp: Span, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, Some(sp), Some(FileLine(sp))); + 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(&mut self , - sp: Span, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, Some(sp), Some(FileLine(sp))); + 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(&mut self , - sp: Span, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, Some(sp), Some(FileLine(sp))); + 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(&mut self, sp: Span) -> &mut Self { - self.span = Some(sp); + pub fn span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { + self.span = Some(sp.into()); self } @@ -237,7 +317,7 @@ impl<'a> DiagnosticBuilder<'a> { /// struct_* methods on Handler. fn new(emitter: &'a RefCell<Box<Emitter>>, level: Level, - message: &str) -> DiagnosticBuilder<'a> { + message: &str) -> DiagnosticBuilder<'a> { DiagnosticBuilder { emitter: emitter, level: level, @@ -253,7 +333,7 @@ impl<'a> DiagnosticBuilder<'a> { fn sub(&mut self, level: Level, message: &str, - span: Option<Span>, + span: Option<MultiSpan>, render_span: Option<RenderSpan>) { let sub = SubDiagnostic { level: level, @@ -290,7 +370,7 @@ pub struct Handler { emit: RefCell<Box<Emitter>>, pub can_emit_warnings: bool, treat_err_as_bug: bool, - delayed_span_bug: RefCell<Option<(codemap::Span, String)>>, + delayed_span_bug: RefCell<Option<(MultiSpan, String)>>, } impl Handler { @@ -320,10 +400,10 @@ impl Handler { DiagnosticBuilder::new(&self.emit, Level::Cancelled, "") } - pub fn struct_span_warn<'a>(&'a self, - sp: Span, - msg: &str) - -> DiagnosticBuilder<'a> { + pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self, + sp: S, + msg: &str) + -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); result.span(sp); if !self.can_emit_warnings { @@ -331,11 +411,11 @@ impl Handler { } result } - pub fn struct_span_warn_with_code<'a>(&'a self, - sp: Span, - msg: &str, - code: &str) - -> DiagnosticBuilder<'a> { + pub fn struct_span_warn_with_code<'a, S: Into<MultiSpan>>(&'a self, + sp: S, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); result.span(sp); result.code(code.to_owned()); @@ -351,20 +431,20 @@ impl Handler { } result } - pub fn struct_span_err<'a>(&'a self, - sp: Span, - msg: &str) - -> DiagnosticBuilder<'a> { + pub fn struct_span_err<'a, S: Into<MultiSpan>>(&'a self, + sp: S, + msg: &str) + -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); result.span(sp); result } - pub fn struct_span_err_with_code<'a>(&'a self, - sp: Span, - msg: &str, - code: &str) - -> DiagnosticBuilder<'a> { + pub fn struct_span_err_with_code<'a, S: Into<MultiSpan>>(&'a self, + sp: S, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); result.span(sp); @@ -375,20 +455,20 @@ impl Handler { self.bump_err_count(); DiagnosticBuilder::new(&self.emit, Level::Error, msg) } - pub fn struct_span_fatal<'a>(&'a self, - sp: Span, - msg: &str) - -> DiagnosticBuilder<'a> { + pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self, + sp: S, + msg: &str) + -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); result.span(sp); result } - pub fn struct_span_fatal_with_code<'a>(&'a self, - sp: Span, - msg: &str, - code: &str) - -> DiagnosticBuilder<'a> { + pub fn struct_span_fatal_with_code<'a, S: Into<MultiSpan>>(&'a self, + sp: S, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { self.bump_err_count(); let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); result.span(sp); @@ -408,58 +488,59 @@ impl Handler { err.cancel(); } - pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError { + pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit(Some(sp), msg, Fatal); + self.emit(Some(&sp.into()), msg, Fatal); self.bump_err_count(); return FatalError; } - pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError { + pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) + -> FatalError { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit_with_code(Some(sp), msg, code, Fatal); + self.emit_with_code(Some(&sp.into()), msg, code, Fatal); self.bump_err_count(); return FatalError; } - pub fn span_err(&self, sp: Span, msg: &str) { + pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { if self.treat_err_as_bug { self.span_bug(sp, msg); } - self.emit(Some(sp), msg, Error); + self.emit(Some(&sp.into()), msg, Error); self.bump_err_count(); } - pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) { + 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), msg, code, Error); + self.emit_with_code(Some(&sp.into()), msg, code, Error); self.bump_err_count(); } - pub fn span_warn(&self, sp: Span, msg: &str) { - self.emit(Some(sp), msg, Warning); + pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { + self.emit(Some(&sp.into()), msg, Warning); } - pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) { - self.emit_with_code(Some(sp), msg, code, 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); } - pub fn span_bug(&self, sp: Span, msg: &str) -> ! { - self.emit(Some(sp), msg, Bug); + pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { + self.emit(Some(&sp.into()), msg, Bug); panic!(ExplicitBug); } - pub fn delay_span_bug(&self, sp: Span, msg: &str) { + pub fn delay_span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { let mut delayed = self.delayed_span_bug.borrow_mut(); - *delayed = Some((sp, msg.to_string())); + *delayed = Some((sp.into(), msg.to_string())); } - pub fn span_bug_no_panic(&self, sp: Span, msg: &str) { - self.emit(Some(sp), msg, Bug); + pub fn span_bug_no_panic<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { + self.emit(Some(&sp.into()), msg, Bug); self.bump_err_count(); } - pub fn span_note_without_error(&self, sp: Span, msg: &str) { - self.emit.borrow_mut().emit(Some(sp), msg, None, Note); + 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); } - pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { + pub fn span_unimpl<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); } pub fn fatal(&self, msg: &str) -> FatalError { @@ -502,15 +583,14 @@ impl Handler { pub fn has_errors(&self) -> bool { self.err_count.get() > 0 } - pub fn abort_if_errors(&self) { let s; match self.err_count.get() { 0 => { let delayed_bug = self.delayed_span_bug.borrow(); match *delayed_bug { - Some((span, ref errmsg)) => { - self.span_bug(span, errmsg); + Some((ref span, ref errmsg)) => { + self.span_bug(span.clone(), errmsg); }, _ => {} } @@ -526,27 +606,24 @@ impl Handler { panic!(self.fatal(&s)); } - pub fn emit(&self, - sp: Option<Span>, + msp: Option<&MultiSpan>, msg: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(sp, msg, None, lvl); + self.emit.borrow_mut().emit(msp, msg, None, lvl); } - pub fn emit_with_code(&self, - sp: Option<Span>, + msp: Option<&MultiSpan>, msg: &str, code: &str, lvl: Level) { if lvl == Warning && !self.can_emit_warnings { return } - self.emit.borrow_mut().emit(sp, msg, Some(code), lvl); + self.emit.borrow_mut().emit(msp, msg, Some(code), lvl); } - - pub fn custom_emit(&self, sp: RenderSpan, msg: &str, lvl: Level) { + 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(sp, msg, lvl); + self.emit.borrow_mut().custom_emit(&rsp, msg, lvl); } } |
