diff options
| author | Jonathan Turner <jturner@mozilla.com> | 2016-07-12 15:18:16 -0400 |
|---|---|---|
| committer | Jonathan Turner <jturner@mozilla.com> | 2016-07-14 07:57:46 -0400 |
| commit | 2f2c3e178325dc1837badcd7573c2c0905fab979 (patch) | |
| tree | 612638d11f7a89f81c5ed7762b478affcb03c209 /src/librustc_errors | |
| parent | f481879d2ae82a6f6ebe33202d4a1cfa8aece5ed (diff) | |
| download | rust-2f2c3e178325dc1837badcd7573c2c0905fab979.tar.gz rust-2f2c3e178325dc1837badcd7573c2c0905fab979.zip | |
DCE and fixing some internal tests
Diffstat (limited to 'src/librustc_errors')
| -rw-r--r-- | src/librustc_errors/emitter.rs | 406 | ||||
| -rw-r--r-- | src/librustc_errors/lib.rs | 10 | ||||
| -rw-r--r-- | src/librustc_errors/snippet.rs | 733 |
3 files changed, 34 insertions, 1115 deletions
diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 5147318d4a6..901cd3403c1 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -14,13 +14,12 @@ use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, LineInfo, use registry; use check_old_skool; -use {Level, RenderSpan, CodeSuggestion, DiagnosticBuilder, CodeMapper}; +use {Level, CodeSuggestion, DiagnosticBuilder, CodeMapper}; use RenderSpan::*; -use Level::*; -use snippet::{SnippetData, StyledString, Style, FormatMode, Annotation, Line}; +use snippet::{StyledString, Style, FormatMode, Annotation, Line}; use styled_buffer::StyledBuffer; -use std::{cmp, fmt}; +use std::cmp; use std::io::prelude::*; use std::io; use std::rc::Rc; @@ -73,10 +72,6 @@ pub struct EmitterWriter { registry: Option<registry::Registry>, cm: Option<Rc<CodeMapper>>, - /// Is this the first error emitted thus far? If not, we emit a - /// `\n` before the top-level errors. - first: bool, - // For now, allow an old-school mode while we transition format_mode: FormatMode } @@ -112,13 +107,11 @@ impl EmitterWriter { EmitterWriter { dst: dst, registry: registry, cm: code_map, - first: true, format_mode: format_mode.clone() } } else { EmitterWriter { dst: Raw(Box::new(io::stderr())), registry: registry, cm: code_map, - first: true, format_mode: format_mode.clone() } } } @@ -131,23 +124,9 @@ impl EmitterWriter { EmitterWriter { dst: Raw(dst), registry: registry, cm: code_map, - first: true, format_mode: format_mode.clone() } } - fn emit_message(&mut self, - rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - is_header: bool, - show_snippet: bool) { - match self.emit_message_(rsp, msg, code, lvl, is_header, show_snippet) { - Ok(()) => { } - Err(e) => panic!("failed to emit error: {}", e) - } - } - fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec<FileWithAnnotatedLines> { fn add_annotation_to_file(file_vec: &mut Vec<FileWithAnnotatedLines>, file: Rc<FileMap>, @@ -187,7 +166,7 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - let mut lo = cm.lookup_char_pos(span_label.span.lo); + let lo = cm.lookup_char_pos(span_label.span.lo); let mut hi = cm.lookup_char_pos(span_label.span.hi); let mut is_minimized = false; @@ -478,7 +457,7 @@ impl EmitterWriter { if msp.primary_spans().is_empty() && msp.span_labels().is_empty() && is_secondary { // This is a secondary message with no span info - for i in 0..max_line_num_len { + for _ in 0..max_line_num_len { buffer.prepend(0, " ", Style::NoStyle); } draw_note_separator(&mut buffer, 0, max_line_num_len + 1); @@ -511,7 +490,7 @@ impl EmitterWriter { cm.lookup_char_pos(primary_span.lo) } else { // If we don't have span information, emit and exit - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); }; if let Ok(pos) = @@ -526,19 +505,19 @@ impl EmitterWriter { let is_primary = primary_lo.file.name == annotated_file.file.name; if is_primary { // remember where we are in the output buffer for easy reference - let mut buffer_msg_line_offset = buffer.num_lines(); + let buffer_msg_line_offset = buffer.num_lines(); buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber); let loc = primary_lo.clone(); buffer.append(buffer_msg_line_offset, &format!("{}:{}:{}", loc.file.name, loc.line, loc.col.0 + 1), Style::LineAndColumn); - for i in 0..max_line_num_len { + for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle); } } else { // remember where we are in the output buffer for easy reference - let mut buffer_msg_line_offset = buffer.num_lines(); + let buffer_msg_line_offset = buffer.num_lines(); // Add spacing line draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); @@ -548,13 +527,13 @@ impl EmitterWriter { buffer.append(buffer_msg_line_offset + 1, &annotated_file.file.name, Style::LineAndColumn); - for i in 0..max_line_num_len { + for _ in 0..max_line_num_len { buffer.prepend(buffer_msg_line_offset + 1, " ", Style::NoStyle); } } // Put in the spacer between the location and annotated source - let mut buffer_msg_line_offset = buffer.num_lines(); + let buffer_msg_line_offset = buffer.num_lines(); draw_col_separator(&mut buffer, buffer_msg_line_offset, max_line_num_len + 1); // Next, output the annotate source for this file @@ -599,7 +578,7 @@ impl EmitterWriter { } // final step: take our styled buffer, render it, then output it - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; Ok(()) } @@ -624,12 +603,6 @@ impl EmitterWriter { assert!(!lines.lines.is_empty()); let complete = suggestion.splice_lines(cm.borrow()); - let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); - let display_lines = &lines.lines[..line_count]; - - let fm = &*lines.file; - // Calculate the widest number to format evenly - let max_digits = line_num_max_digits(display_lines.last().unwrap()); // print the suggestion without any line numbers, but leave // space for them. This helps with lining up with previous @@ -646,7 +619,7 @@ impl EmitterWriter { if let Some(_) = lines.next() { buffer.append(row_num, "...", Style::NoStyle); } - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; } Ok(()) } @@ -664,7 +637,10 @@ impl EmitterWriter { if !db.children.is_empty() { let mut buffer = StyledBuffer::new(); draw_col_separator(&mut buffer, 0, max_line_num_len + 1); - emit_to_destination(&buffer.render(), &db.level, &mut self.dst); + match emit_to_destination(&buffer.render(), &db.level, &mut self.dst) { + Ok(()) => (), + Err(e) => panic!("failed to emit error: {}", e) + } } for child in &db.children { match child.render_span { @@ -704,7 +680,10 @@ impl EmitterWriter { } Err(e) => panic!("failed to emit error: {}", e) } - write!(&mut self.dst, "\n"); + match write!(&mut self.dst, "\n") { + Err(e) => panic!("failed to emit error: {}", e), + _ => () + } } fn emit_message_old_school(&mut self, msp: &MultiSpan, @@ -744,7 +723,7 @@ impl EmitterWriter { } if !show_snippet { - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); } @@ -752,13 +731,13 @@ impl EmitterWriter { // print any filename or anything for those. match msp.primary_span() { Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => { - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); } _ => { } } - let mut annotated_files = self.preprocess_annotations(msp); + let annotated_files = self.preprocess_annotations(msp); if let (Some(ref cm), Some(ann_file), Some(ref primary_span)) = (self.cm.as_ref(), annotated_files.first(), msp.primary_span().as_ref()) { @@ -781,7 +760,7 @@ impl EmitterWriter { buffer.puts(line_offset, 0, &file_pos, Style::FileNameStyle); buffer.puts(line_offset, file_pos_len, &source_string, Style::Quotation); // Sort the annotations by (start, end col) - let mut annotations = ann_file.lines[0].annotations.clone(); + let annotations = ann_file.lines[0].annotations.clone(); // Next, create the highlight line. for annotation in &annotations { @@ -830,7 +809,7 @@ impl EmitterWriter { } // final step: take our styled buffer, render it, then output it - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; Ok(()) } fn emit_suggestion_old_school(&mut self, @@ -874,7 +853,7 @@ impl EmitterWriter { let mut row_num = 1; for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { buffer.append(row_num, &fm.name, Style::FileNameStyle); - for i in 0..max_digits+2 { + for _ in 0..max_digits+2 { buffer.append(row_num, &" ", Style::NoStyle); } buffer.append(row_num, line, Style::NoStyle); @@ -885,7 +864,7 @@ impl EmitterWriter { if let Some(_) = lines.next() { buffer.append(row_num, "...", Style::NoStyle); } - emit_to_destination(&buffer.render(), level, &mut self.dst); + emit_to_destination(&buffer.render(), level, &mut self.dst)?; } Ok(()) } @@ -905,7 +884,7 @@ impl EmitterWriter { }; match child.render_span { - Some(FullSpan(ref msp)) => { + Some(FullSpan(_)) => { match self.emit_message_old_school(&span, &child.message, &None, @@ -940,235 +919,6 @@ impl EmitterWriter { } } - fn emit_message_(&mut self, - rsp: &RenderSpan, - msg: &str, - code: Option<&str>, - lvl: Level, - is_header: bool, - show_snippet: bool) - -> io::Result<()> { - let old_school = match self.format_mode { - FormatMode::NewErrorFormat => false, - FormatMode::OriginalErrorFormat => true, - FormatMode::EnvironmentSelected => check_old_skool() - }; - - if is_header { - if self.first { - self.first = false; - } else { - if !old_school { - write!(self.dst, "\n")?; - } - } - } - - 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; - if old_school { - let loc = match rsp.span().primary_span() { - Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), - Some(ps) => if let Some(ref cm) = self.cm { - cm.span_to_string(ps) - } else { - "".to_string() - }, - None => "".to_string() - }; - print_diagnostic(&mut self.dst, &loc, lvl, msg, Some(code))? - } - else { - print_diagnostic(&mut self.dst, "", lvl, msg, Some(&code_with_explain))? - } - } - _ => { - if old_school { - let loc = match rsp.span().primary_span() { - Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), - Some(ps) => if let Some(ref cm) = self.cm { - cm.span_to_string(ps) - } else { - "".to_string() - }, - None => "".to_string() - }; - print_diagnostic(&mut self.dst, &loc, lvl, msg, code)? - } - else { - print_diagnostic(&mut self.dst, "", lvl, msg, code)? - } - } - } - - if !show_snippet { - return Ok(()); - } - - // Watch out for various nasty special spans; don't try to - // print any filename or anything for those. - match rsp.span().primary_span() { - Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => { - return Ok(()); - } - _ => { } - } - - // Otherwise, print out the snippet etc as needed. - match *rsp { - FullSpan(ref msp) => { - self.highlight_lines(msp, lvl)?; - if let Some(primary_span) = msp.primary_span() { - self.print_macro_backtrace(primary_span)?; - } - } - Suggestion(ref suggestion) => { - self.highlight_suggestion(suggestion)?; - if let Some(primary_span) = rsp.span().primary_span() { - self.print_macro_backtrace(primary_span)?; - } - } - } - if old_school { - match code { - Some(code) if self.registry.as_ref() - .and_then(|registry| registry.find_description(code)) - .is_some() => { - let loc = match rsp.span().primary_span() { - Some(COMMAND_LINE_SP) | Some(DUMMY_SP) => "".to_string(), - Some(ps) => if let Some(ref cm) = self.cm { - cm.span_to_string(ps) - } else { - "".to_string() - }, - None => "".to_string() - }; - let msg = "run `rustc --explain ".to_string() + &code.to_string() + - "` to see a detailed explanation"; - print_diagnostic(&mut self.dst, &loc, Level::Help, &msg, - None)? - } - _ => () - } - } - Ok(()) - } - - fn highlight_suggestion(&mut self, suggestion: &CodeSuggestion) -> io::Result<()> - { - use std::borrow::Borrow; - - let primary_span = suggestion.msp.primary_span().unwrap(); - if let Some(ref cm) = self.cm { - let lines = cm.span_to_lines(primary_span).unwrap(); - - assert!(!lines.lines.is_empty()); - - let complete = suggestion.splice_lines(cm.borrow()); - let line_count = cmp::min(lines.lines.len(), MAX_HIGHLIGHT_LINES); - let display_lines = &lines.lines[..line_count]; - - let fm = &*lines.file; - // Calculate the widest number to format evenly - let max_digits = line_num_max_digits(display_lines.last().unwrap()); - - // 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 mut lines = complete.lines(); - for line in lines.by_ref().take(MAX_HIGHLIGHT_LINES) { - write!(&mut self.dst, "{0}:{1:2$} {3}\n", - fm.name, "", max_digits, line)?; - } - - // if we elided some lines, add an ellipsis - if let Some(_) = lines.next() { - write!(&mut self.dst, "{0:1$} {0:2$} ...\n", - "", fm.name.len(), max_digits)?; - } - } - Ok(()) - } - - pub fn highlight_lines(&mut self, - msp: &MultiSpan, - lvl: Level) - -> io::Result<()> - { - // Check to see if we have any lines to highlight, exit early if not - match self.cm { - None => return Ok(()), - _ => () - } - - let old_school = match self.format_mode { - FormatMode::NewErrorFormat => false, - FormatMode::OriginalErrorFormat => true, - FormatMode::EnvironmentSelected => check_old_skool() - }; - - let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(), - msp.primary_span(), - self.format_mode.clone()); - if old_school { - let mut output_vec = vec![]; - - for span_label in msp.span_labels() { - let mut snippet_data = SnippetData::new(self.cm.as_ref().unwrap().clone(), - Some(span_label.span), - self.format_mode.clone()); - - snippet_data.push(span_label.span, - span_label.is_primary, - span_label.label); - if span_label.is_primary { - output_vec.insert(0, snippet_data); - } - else { - output_vec.push(snippet_data); - } - } - - for snippet_data in output_vec.iter() { - /* - 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()?; - } - write!(&mut self.dst, "\n")?; - } - */ - emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst); - } - } - else { - for span_label in msp.span_labels() { - snippet_data.push(span_label.span, - span_label.is_primary, - span_label.label); - } - emit_to_destination(&snippet_data.render_lines(), &lvl, &mut self.dst); - /* - 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()?; - } - write!(&mut self.dst, "\n")?; - } - */ - } - Ok(()) - } - fn render_macro_backtrace_old_school(&mut self, sp: &Span, buffer: &mut StyledBuffer) -> io::Result<()> { @@ -1192,24 +942,6 @@ impl EmitterWriter { } Ok(()) } - fn print_macro_backtrace(&mut self, - sp: Span) - -> io::Result<()> { - if let Some(ref cm) = self.cm { - for trace in cm.macro_backtrace(sp) { - let mut diag_string = - format!("in this expansion of {}", trace.macro_decl_name); - if let Some(def_site_span) = trace.def_site_span { - diag_string.push_str( - &format!(" (defined in {})", - cm.span_to_filename(def_site_span))); - } - let snippet = cm.span_to_string(trace.call_site); - print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?; - } - } - Ok(()) - } } fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) { @@ -1230,11 +962,11 @@ fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>, dst: &mut Destination) -> io::Result<()> { for line in rendered_buffer { for part in line { - dst.apply_style(lvl.clone(), part.style); - write!(dst, "{}", part.text); + dst.apply_style(lvl.clone(), part.style)?; + write!(dst, "{}", part.text)?; dst.reset_attrs()?; } - write!(dst, "\n"); + write!(dst, "\n")?; } Ok(()) } @@ -1249,40 +981,6 @@ fn line_num_max_digits(line: &LineInfo) -> usize { digits } -fn print_diagnostic(dst: &mut Destination, - topic: &str, - lvl: Level, - msg: &str, - code: Option<&str>) - -> io::Result<()> { - if !topic.is_empty() { - let old_school = check_old_skool(); - if !old_school { - write!(dst, "{}: ", topic)?; - } - else { - write!(dst, "{} ", topic)?; - } - dst.reset_attrs()?; - } - 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(()) -} - #[cfg(unix)] fn stderr_isatty() -> bool { use libc; @@ -1374,46 +1072,6 @@ impl Destination { } Ok(()) } - - fn print_maybe_styled(&mut self, - args: fmt::Arguments, - color: term::Attr, - print_newline_at_end: bool) - -> io::Result<()> { - match *self { - Terminal(ref mut t) => { - t.attr(color)?; - // If `msg` ends in a newline, we need to reset the color before - // the newline. We're making the assumption that we end up writing - // to a `LineBufferedWriter`, which means that emitting the reset - // after the newline ends up buffering the reset until we print - // another line or exit. Buffering the reset is a problem if we're - // sharing the terminal with any other programs (e.g. other rustc - // instances via `make -jN`). - // - // Note that if `msg` contains any internal newlines, this will - // result in the `LineBufferedWriter` flushing twice instead of - // once, which still leaves the opportunity for interleaved output - // to be miscolored. We assume this is rare enough that we don't - // have to worry about it. - t.write_fmt(args)?; - t.reset()?; - if print_newline_at_end { - t.write_all(b"\n") - } else { - Ok(()) - } - } - Raw(ref mut w) => { - w.write_fmt(args)?; - if print_newline_at_end { - w.write_all(b"\n") - } else { - Ok(()) - } - } - } - } } impl Write for Destination { diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 33781bed759..d5340e66ff0 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -82,16 +82,6 @@ pub trait CodeMapper { fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace>; } -impl RenderSpan { - fn span(&self) -> &MultiSpan { - match *self { - FullSpan(ref msp) | - Suggestion(CodeSuggestion { ref msp, .. }) => - msp - } - } -} - impl CodeSuggestion { /// Returns the assembled code suggestion. pub fn splice_lines(&self, cm: &CodeMapper) -> String { diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index 525c83499fb..2f94a7f6832 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -10,13 +10,9 @@ // Code for annotating snippets. -use syntax_pos::{Span, FileMap, CharPos, LineInfo}; -use check_old_skool; +use syntax_pos::{Span, FileMap}; use CodeMapper; -use styled_buffer::StyledBuffer; -use std::cmp; use std::rc::Rc; -use std::mem; use {Level}; #[derive(Clone)] @@ -78,14 +74,6 @@ pub struct Annotation { pub label: Option<String>, } -/* -#[derive(Debug)] -pub struct RenderedLine { - pub text: Vec<StyledString>, - pub kind: RenderedLineKind, -} -*/ - #[derive(Debug)] pub struct StyledString { pub text: String, @@ -108,721 +96,4 @@ pub enum Style { NoStyle, ErrorCode, Level(Level), -} - -/* -#[derive(Debug, Clone)] -pub enum RenderedLineKind { - PrimaryFileName, - OtherFileName, - SourceText { - file: Rc<FileMap>, - line_index: usize, - }, - Annotations, - Elision, -} -*/ - -impl SnippetData { - pub fn new(codemap: Rc<CodeMapper>, - primary_span: Option<Span>, - format_mode: FormatMode) // (*) - -> Self { - // (*) The primary span indicates the file that must appear - // first, and which will have a line number etc in its - // name. Outside of tests, this is always `Some`, but for many - // tests it's not relevant to test this portion of the logic, - // and it's tedious to pick a primary span (read: tedious to - // port older tests that predate the existence of a primary - // span). - - debug!("SnippetData::new(primary_span={:?})", primary_span); - - let mut data = SnippetData { - codemap: codemap.clone(), - files: vec![], - format_mode: format_mode.clone() - }; - if let Some(primary_span) = primary_span { - let lo = codemap.lookup_char_pos(primary_span.lo); - data.files.push( - FileInfo { - file: lo.file, - primary_span: Some(primary_span), - lines: vec![], - format_mode: format_mode.clone(), - }); - } - data - } - - pub fn push(&mut self, span: Span, is_primary: bool, label: Option<String>) { - debug!("SnippetData::push(span={:?}, is_primary={}, label={:?})", - span, is_primary, label); - - let file_lines = match self.codemap.span_to_lines(span) { - Ok(file_lines) => file_lines, - Err(_) => { - // ignore unprintable spans completely. - return; - } - }; - - self.file(&file_lines.file) - .push_lines(&file_lines.lines, is_primary, label); - } - - fn file(&mut self, file_map: &Rc<FileMap>) -> &mut FileInfo { - let index = self.files.iter().position(|f| f.file.name == file_map.name); - if let Some(index) = index { - return &mut self.files[index]; - } - - self.files.push( - FileInfo { - file: file_map.clone(), - lines: vec![], - primary_span: None, - format_mode: self.format_mode.clone() - }); - self.files.last_mut().unwrap() - } - - pub fn render_lines(&self) -> Vec<Vec<StyledString>> { - debug!("SnippetData::render_lines()"); - - let mut rendered_lines: Vec<_> = - self.files.iter() - .flat_map(|f| f.render_file_lines(&self.codemap)) - .collect(); - //prepend_prefixes(&mut rendered_lines, &self.format_mode); - //trim_lines(&mut rendered_lines); - rendered_lines - } -} - -pub trait StringSource { - fn make_string(self) -> String; -} - -impl StringSource for String { - fn make_string(self) -> String { - self - } -} - -impl StringSource for Vec<char> { - fn make_string(self) -> String { - self.into_iter().collect() - } -} - -/* -impl<S> From<(S, Style, RenderedLineKind)> for RenderedLine - where S: StringSource -{ - fn from((text, style, kind): (S, Style, RenderedLineKind)) -> Self { - RenderedLine { - text: vec![StyledString { - text: text.make_string(), - style: style, - }], - kind: kind, - } - } -} - -impl<S1,S2> From<(S1, Style, S2, Style, RenderedLineKind)> for RenderedLine - where S1: StringSource, S2: StringSource -{ - fn from(tuple: (S1, Style, S2, Style, RenderedLineKind)) -> Self { - let (text1, style1, text2, style2, kind) = tuple; - RenderedLine { - text: vec![ - StyledString { - text: text1.make_string(), - style: style1, - }, - StyledString { - text: text2.make_string(), - style: style2, - } - ], - kind: kind, - } - } -} - -impl RenderedLine { - fn trim_last(&mut self) { - if let Some(last_text) = self.text.last_mut() { - let len = last_text.text.trim_right().len(); - last_text.text.truncate(len); - } - } -} - -impl RenderedLineKind { - fn prefix(&self) -> StyledString { - match *self { - RenderedLineKind::SourceText { file: _, line_index } => - StyledString { - text: format!("{}", line_index + 1), - style: Style::LineNumber, - }, - RenderedLineKind::Elision => - StyledString { - text: String::from("..."), - style: Style::LineNumber, - }, - RenderedLineKind::PrimaryFileName | - RenderedLineKind::OtherFileName | - RenderedLineKind::Annotations => - StyledString { - text: String::from(""), - style: Style::LineNumber, - }, - } - } -} -*/ - -impl FileInfo { - fn get_max_line_num(&self) -> usize { - let mut max = 0; - - for line in &self.lines { - if line.line_index > max { - max = line.line_index; - } - } - max - } - - fn push_lines(&mut self, - lines: &[LineInfo], - is_primary: bool, - label: Option<String>) { - assert!(lines.len() > 0); - - // If a span covers multiple lines, we reduce it to a single - // point at the start of the span. This means that instead - // of producing output like this: - // - // ``` - // --> foo.rs:2:1 - // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>) - // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // 3 |> -> Set<LR0Item<'grammar>> - // |> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - // (and so on) - // ``` - // - // we produce: - // - // ``` - // --> foo.rs:2:1 - // 2 |> fn conflicting_items<'grammar>(state: &LR0State<'grammar>) - // ^ - // ``` - // - // Basically, although this loses information, multi-line spans just - // never look good. - - let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 { - (lines[0].line_index, lines[0].start_col, lines[0].end_col, false) - } else { - (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), true) - }; - - // Watch out for "empty spans". If we get a span like 6..6, we - // want to just display a `^` at 6, so convert that to - // 6..7. This is degenerate input, but it's best to degrade - // gracefully -- and the parser likes to suply a span like - // that for EOF, in particular. - if start_col == end_col { - end_col.0 += 1; - } - - let index = self.ensure_source_line(line); - self.lines[index].push_annotation(start_col, - end_col, - is_primary, - is_minimized, - label); - } - - /// Ensure that we have a `Line` struct corresponding to - /// `line_index` in the file. If we already have some other lines, - /// then this will add the intervening lines to ensure that we - /// have a complete snippet. (Note that when we finally display, - /// some of those lines may be elided.) - fn ensure_source_line(&mut self, line_index: usize) -> usize { - if self.lines.is_empty() { - self.lines.push(Line::new(line_index)); - return 0; - } - - // Find the range of lines we have thus far. - let first_line_index = self.lines.first().unwrap().line_index; - let last_line_index = self.lines.last().unwrap().line_index; - assert!(first_line_index <= last_line_index); - - // If the new line is lower than all the lines we have thus - // far, then insert the new line and any intervening lines at - // the front. In a silly attempt at micro-optimization, we - // don't just call `insert` repeatedly, but instead make a new - // (empty) vector, pushing the new lines onto it, and then - // appending the old vector. - if line_index < first_line_index { - let lines = mem::replace(&mut self.lines, vec![]); - self.lines.extend( - (line_index .. first_line_index) - .map(|line| Line::new(line)) - .chain(lines)); - return 0; - } - - // If the new line comes after the ones we have so far, insert - // lines for it. - if line_index > last_line_index { - self.lines.extend( - (last_line_index+1 .. line_index+1) - .map(|line| Line::new(line))); - return self.lines.len() - 1; - } - - // Otherwise it should already exist. - return line_index - first_line_index; - } - - fn render_file_lines(&self, codemap: &Rc<CodeMapper>) -> Vec<Vec<StyledString>> { - let old_school = match self.format_mode { - FormatMode::OriginalErrorFormat => true, - FormatMode::NewErrorFormat => false, - FormatMode::EnvironmentSelected => check_old_skool() - }; - - let mut lines_iter = self.lines.iter(); - let mut output = vec![]; - - // First insert the name of the file. - if !old_school { - match self.primary_span { - Some(span) => { - let lo = codemap.lookup_char_pos(span.lo); - output.push(vec![StyledString { - text: lo.file.name.clone(), - style: Style::FileNameStyle, - }, StyledString { - text: format!(":{}:{}", lo.line, lo.col.0 + 1), - style: Style::LineAndColumn, - }]); - output.push(vec![StyledString { - text: "".to_string(), - style: Style::FileNameStyle, - }]); - } - None => { - output.push(vec![StyledString { - text: self.file.name.clone(), - style: Style::FileNameStyle, - }]); - output.push(vec![StyledString { - text: "".to_string(), - style: Style::FileNameStyle, - }]); - } - } - } - - let mut next_line = lines_iter.next(); - while next_line.is_some() { - // Consume lines with annotations. - while let Some(line) = next_line { - if line.annotations.is_empty() { break; } - - let mut rendered_lines = self.render_line(line); - assert!(!rendered_lines.is_empty()); - if old_school { - match self.primary_span { - Some(span) => { - let lo = codemap.lookup_char_pos(span.lo); - let hi = codemap.lookup_char_pos(span.hi); - //Before each secondary line in old skool-mode, print the label - //as an old-style note - if !line.annotations[0].is_primary { - if let Some(ann) = line.annotations[0].label.clone() { - output.push(vec![StyledString { - text: lo.file.name.clone(), - style: Style::FileNameStyle, - }, StyledString { - text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1, - hi.line, hi.col.0+1), - style: Style::LineAndColumn, - }, StyledString { - text: format!("note: "), - style: Style::OldSchoolNote, - }, StyledString { - text: format!("{}", ann), - style: Style::OldSchoolNoteText, - }]); - } - } - rendered_lines[0].insert(0, StyledString { - text: format!(":{} ", lo.line), - style: Style::LineAndColumn, - }); - rendered_lines[0].insert(0, StyledString { - text: lo.file.name.clone(), - style: Style::FileNameStyle, - }); - let gap_amount = - rendered_lines[0][0].text.len() + - rendered_lines[0][1].text.len(); - assert!(rendered_lines.len() >= 2, - "no annotations resulted from: {:?}", - line); - for i in 1..rendered_lines.len() { - rendered_lines[i].insert(0, StyledString { - text: vec![" "; gap_amount].join(""), - style: Style::NoStyle - }); - } - } - _ =>() - } - } - output.append(&mut rendered_lines); - next_line = lines_iter.next(); - } - - // Emit lines without annotations, but only if they are - // followed by a line with an annotation. - let unannotated_line = next_line; - let mut unannotated_lines = 0; - while let Some(line) = next_line { - if !line.annotations.is_empty() { break; } - unannotated_lines += 1; - next_line = lines_iter.next(); - } - if unannotated_lines > 1 { - output.push(vec![StyledString{ text: String::new(), style: Style::NoStyle}]); - } else if let Some(line) = unannotated_line { - output.append(&mut self.render_line(line)); - } - } - - output - } - - fn render_line(&self, line: &Line) -> Vec<Vec<StyledString>> { - let old_school = match self.format_mode { - FormatMode::OriginalErrorFormat => true, - FormatMode::NewErrorFormat => false, - FormatMode::EnvironmentSelected => check_old_skool() - }; - - let source_string = self.file.get_line(line.line_index) - .unwrap_or(""); - /* - let source_kind = RenderedLineKind::SourceText { - file: self.file.clone(), - line_index: line.line_index, - }; - */ - - let mut styled_buffer = StyledBuffer::new(); - - // First create the source line we will highlight. - styled_buffer.append(0, &source_string, Style::Quotation); - - if line.annotations.is_empty() { - return styled_buffer.render(); - } - - // We want to display like this: - // - // vec.push(vec.pop().unwrap()); - // --- ^^^ _ previous borrow ends here - // | | - // | error occurs here - // previous borrow of `vec` occurs here - // - // But there are some weird edge cases to be aware of: - // - // vec.push(vec.pop().unwrap()); - // -------- - previous borrow ends here - // || - // |this makes no sense - // previous borrow of `vec` occurs here - // - // For this reason, we group the lines into "highlight lines" - // and "annotations lines", where the highlight lines have the `~`. - - //let mut highlight_line = Self::whitespace(&source_string); - - // Sort the annotations by (start, end col) - let mut annotations = line.annotations.clone(); - annotations.sort(); - - // Next, create the highlight line. - for annotation in &annotations { - if old_school { - for p in annotation.start_col .. annotation.end_col { - if p == annotation.start_col { - styled_buffer.putc(1, p, '^', - if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::OldSchoolNote - }); - } - else { - styled_buffer.putc(1, p, '~', - if annotation.is_primary { - Style::UnderlinePrimary - } else { - Style::OldSchoolNote - }); - } - } - } - else { - for p in annotation.start_col .. annotation.end_col { - if annotation.is_primary { - styled_buffer.putc(1, p, '^', Style::UnderlinePrimary); - if !annotation.is_minimized { - styled_buffer.set_style(0, p, Style::UnderlinePrimary); - } - } else { - styled_buffer.putc(1, p, '-', Style::UnderlineSecondary); - if !annotation.is_minimized { - styled_buffer.set_style(0, p, Style::UnderlineSecondary); - } - } - } - } - } - - // Now we are going to write labels in. To start, we'll exclude - // the annotations with no labels. - let (labeled_annotations, unlabeled_annotations): (Vec<_>, _) = - annotations.into_iter() - .partition(|a| a.label.is_some()); - - // If there are no annotations that need text, we're done. - if labeled_annotations.is_empty() { - return styled_buffer.render(); - } - if old_school { - return styled_buffer.render(); - } - - // Now add the text labels. We try, when possible, to stick the rightmost - // annotation at the end of the highlight line: - // - // vec.push(vec.pop().unwrap()); - // --- --- - previous borrow ends here - // - // But sometimes that's not possible because one of the other - // annotations overlaps it. For example, from the test - // `span_overlap_label`, we have the following annotations - // (written on distinct lines for clarity): - // - // fn foo(x: u32) { - // -------------- - // - - // - // In this case, we can't stick the rightmost-most label on - // the highlight line, or we would get: - // - // fn foo(x: u32) { - // -------- x_span - // | - // fn_span - // - // which is totally weird. Instead we want: - // - // fn foo(x: u32) { - // -------------- - // | | - // | x_span - // fn_span - // - // which is...less weird, at least. In fact, in general, if - // the rightmost span overlaps with any other span, we should - // use the "hang below" version, so we can at least make it - // clear where the span *starts*. - let mut labeled_annotations = &labeled_annotations[..]; - match labeled_annotations.split_last().unwrap() { - (last, previous) => { - if previous.iter() - .chain(&unlabeled_annotations) - .all(|a| !overlaps(a, last)) - { - // append the label afterwards; we keep it in a separate - // string - let highlight_label: String = format!(" {}", last.label.as_ref().unwrap()); - if last.is_primary { - styled_buffer.append(1, &highlight_label, Style::LabelPrimary); - } else { - styled_buffer.append(1, &highlight_label, Style::LabelSecondary); - } - labeled_annotations = previous; - } - } - } - - // If that's the last annotation, we're done - if labeled_annotations.is_empty() { - return styled_buffer.render(); - } - - for (index, annotation) in labeled_annotations.iter().enumerate() { - // Leave: - // - 1 extra line - // - One line for each thing that comes after - let comes_after = labeled_annotations.len() - index - 1; - let blank_lines = 3 + comes_after; - - // For each blank line, draw a `|` at our column. The - // text ought to be long enough for this. - for index in 2..blank_lines { - if annotation.is_primary { - styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlinePrimary); - } else { - styled_buffer.putc(index, annotation.start_col, '|', Style::UnderlineSecondary); - } - } - - if annotation.is_primary { - styled_buffer.puts(blank_lines, annotation.start_col, - annotation.label.as_ref().unwrap(), Style::LabelPrimary); - } else { - styled_buffer.puts(blank_lines, annotation.start_col, - annotation.label.as_ref().unwrap(), Style::LabelSecondary); - } - } - - styled_buffer.render() - } -} - -/* -fn prepend_prefixes(rendered_lines: &mut [RenderedLine], format_mode: &FormatMode) { - let old_school = match *format_mode { - FormatMode::OriginalErrorFormat => true, - FormatMode::NewErrorFormat => false, - FormatMode::EnvironmentSelected => check_old_skool() - }; - if old_school { - return; - } - - let prefixes: Vec<_> = - rendered_lines.iter() - .map(|rl| rl.kind.prefix()) - .collect(); - - // find the max amount of spacing we need; add 1 to - // p.text.len() to leave space between the prefix and the - // source text - let padding_len = - prefixes.iter() - .map(|p| if p.text.len() == 0 { 0 } else { p.text.len() + 1 }) - .max() - .unwrap_or(0); - - // Ensure we insert at least one character of padding, so that the - // `-->` arrows can fit etc. - let padding_len = cmp::max(padding_len, 1); - - for (mut prefix, line) in prefixes.into_iter().zip(rendered_lines) { - let extra_spaces = (prefix.text.len() .. padding_len).map(|_| ' '); - prefix.text.extend(extra_spaces); - match line.kind { - RenderedLineKind::Elision => { - line.text.insert(0, prefix); - } - RenderedLineKind::PrimaryFileName => { - // --> filename - // 22 |> - // ^ - // padding_len - let dashes = (0..padding_len - 1).map(|_| ' ') - .chain(Some('-')) - .chain(Some('-')) - .chain(Some('>')) - .chain(Some(' ')); - line.text.insert(0, StyledString {text: dashes.collect(), - style: Style::LineNumber}) - } - RenderedLineKind::OtherFileName => { - // ::: filename - // 22 |> - // ^ - // padding_len - let dashes = (0..padding_len - 1).map(|_| ' ') - .chain(Some(':')) - .chain(Some(':')) - .chain(Some(':')) - .chain(Some(' ')); - line.text.insert(0, StyledString {text: dashes.collect(), - style: Style::LineNumber}) - } - _ => { - line.text.insert(0, prefix); - line.text.insert(1, StyledString {text: String::from("|> "), - style: Style::LineNumber}) - } - } - } -} - -fn trim_lines(rendered_lines: &mut [RenderedLine]) { - for line in rendered_lines { - while !line.text.is_empty() { - line.trim_last(); - if line.text.last().unwrap().text.is_empty() { - line.text.pop(); - } else { - break; - } - } - } -} -*/ - -impl Line { - fn new(line_index: usize) -> Line { - Line { - line_index: line_index, - annotations: vec![] - } - } - - fn push_annotation(&mut self, - start: CharPos, - end: CharPos, - is_primary: bool, - is_minimized: bool, - label: Option<String>) { - self.annotations.push(Annotation { - start_col: start.0, - end_col: end.0, - is_primary: is_primary, - is_minimized: is_minimized, - label: label, - }); - } -} - -fn overlaps(a1: &Annotation, - a2: &Annotation) - -> bool -{ - (a2.start_col .. a2.end_col).contains(a1.start_col) || - (a1.start_col .. a1.end_col).contains(a2.start_col) -} +} \ No newline at end of file |
