diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2015-04-09 14:48:15 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2015-04-10 06:11:28 -0400 |
| commit | 906a9728ffd4cd9f40c96d7704260baf17845651 (patch) | |
| tree | 448fb8de4dda0fb0d1e963069493ef5d55abd4de | |
| parent | 5156b3a6cd1c60982f0bea9f3b7243f66cab9bb5 (diff) | |
| download | rust-906a9728ffd4cd9f40c96d7704260baf17845651.tar.gz rust-906a9728ffd4cd9f40c96d7704260baf17845651.zip | |
Add a new `span_suggestion` infrastructure. This lets you edit a snippet
of text (perhaps obtained by span_snippet) and then splice that edited form back into the original file in the form of a suggestion.
| -rw-r--r-- | src/librustc/session/mod.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/diagnostic.rs | 66 |
2 files changed, 72 insertions, 1 deletions
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 148f484b0ed..88faf1cb68a 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -143,6 +143,13 @@ impl Session { pub fn span_end_note(&self, sp: Span, msg: &str) { self.diagnostic().span_end_note(sp, msg) } + + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { + self.diagnostic().span_suggestion(sp, msg, suggestion) + } pub fn span_help(&self, sp: Span, msg: &str) { self.diagnostic().span_help(sp, msg) } diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 32509ba6065..ed7bdcd898e 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -18,6 +18,7 @@ use codemap; use diagnostics; use std::cell::{RefCell, Cell}; +use std::cmp; use std::fmt; use std::io::prelude::*; use std::io; @@ -28,7 +29,7 @@ use libc; /// maximum number of lines we will print for each error; arbitrary. const MAX_LINES: usize = 6; -#[derive(Clone, Copy)] +#[derive(Clone)] pub enum RenderSpan { /// A FullSpan renders with both with an initial line for the /// message, prefixed by file:linenum, followed by a summary of @@ -42,6 +43,12 @@ pub enum RenderSpan { /// of the span). EndSpan(Span), + /// 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), + /// A FileLine renders with just a line for the message prefixed /// by file:linenum. FileLine(Span), @@ -51,6 +58,7 @@ impl RenderSpan { fn span(&self) -> Span { match *self { FullSpan(s) | + Suggestion(s, _) | EndSpan(s) | FileLine(s) => s @@ -124,6 +132,12 @@ impl SpanHandler { pub fn span_help(&self, sp: Span, msg: &str) { self.handler.emit(Some((&self.cm, sp)), msg, Help); } + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { + self.handler.custom_emit(&self.cm, Suggestion(sp, suggestion), msg, Help); + } pub fn fileline_note(&self, sp: Span, msg: &str) { self.handler.custom_emit(&self.cm, FileLine(sp), msg, Note); } @@ -455,6 +469,9 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, EndSpan(_) => { try!(end_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp))); } + Suggestion(_, ref suggestion) => { + try!(highlight_suggestion(dst, cm, sp, suggestion)); + } FileLine(..) => { // no source text in this case! } @@ -479,6 +496,53 @@ fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, Ok(()) } +fn highlight_suggestion(err: &mut EmitterWriter, + cm: &codemap::CodeMap, + sp: Span, + suggestion: &str) + -> io::Result<()> +{ + let lines = cm.span_to_lines(sp); + assert!(!lines.lines.is_empty()); + + // To build up the result, we want to take the snippet from the first + // line that precedes the span, prepend that with the suggestion, and + // then append the snippet from the last line that trails the span. + let fm = &lines.file; + + let first_line = &lines.lines[0]; + let prefix = fm.get_line(first_line.line_index) + .map(|l| &l[..first_line.start_col.0]) + .unwrap_or(""); + + let last_line = lines.lines.last().unwrap(); + let suffix = fm.get_line(last_line.line_index) + .map(|l| &l[last_line.end_col.0..]) + .unwrap_or(""); + + let complete = format!("{}{}{}", prefix, suggestion, suffix); + + // print the suggestion without any line numbers, but leave + // space for them. This helps with lining up with previous + // snippets from the actual error being reported. + let fm = &*lines.file; + let mut lines = complete.lines(); + for (line, line_index) in lines.by_ref().take(MAX_LINES).zip(first_line.line_index..) { + let elided_line_num = format!("{}", line_index+1); + try!(write!(&mut err.dst, "{0}:{1:2$} {3}\n", + fm.name, "", elided_line_num.len(), line)); + } + + // if we elided some lines, add an ellipsis + if lines.next().is_some() { + let elided_line_num = format!("{}", first_line.line_index + MAX_LINES + 1); + try!(write!(&mut err.dst, "{0:1$} {0:2$} ...\n", + "", fm.name.len(), elided_line_num.len())); + } + + Ok(()) +} + fn highlight_lines(err: &mut EmitterWriter, cm: &codemap::CodeMap, sp: Span, |
