From f030b5dbc29b20b964f2cc448d893998080b1a46 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 3 May 2016 06:11:20 -0400 Subject: [PATCH] degrade gracefully with empty spans --- src/libsyntax/errors/snippet/mod.rs | 12 ++++++++- src/libsyntax/errors/snippet/test.rs | 38 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs index e213f623ab85d..237e6823e0f87 100644 --- a/src/libsyntax/errors/snippet/mod.rs +++ b/src/libsyntax/errors/snippet/mod.rs @@ -376,11 +376,21 @@ impl FileInfo { // Basically, although this loses information, multi-line spans just // never look good. - let (line, start_col, end_col) = if lines.len() == 1 { + let (line, start_col, mut end_col) = if lines.len() == 1 { (lines[0].line_index, lines[0].start_col, lines[0].end_col) } else { (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1)) }; + + // 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, diff --git a/src/libsyntax/errors/snippet/test.rs b/src/libsyntax/errors/snippet/test.rs index 569d11199190c..5a888b488191b 100644 --- a/src/libsyntax/errors/snippet/test.rs +++ b/src/libsyntax/errors/snippet/test.rs @@ -519,3 +519,41 @@ fn span_overlap_label3() { |> ----- bar "#[1..]); } + +#[test] +fn span_empty() { + // In one of the unit tests, we found that the parser sometimes + // gives empty spans, and in particular it supplied an EOF span + // like this one, which points at the very end. We want to + // fallback gracefully in this case. + + let file_text = r#" +fn main() { + struct Foo; + + impl !Sync for Foo {} + + unsafe impl Send for &'static Foo { + // error: cross-crate traits with a default impl, like `core::marker::Send`, + // can only be implemented for a struct/enum type, not + // `&'static Foo` +}"#; + + + let cm = Rc::new(CodeMap::new()); + let foo = cm.new_filemap_and_lines("foo.rs", file_text); + + let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1); + rbrace_span.lo = rbrace_span.hi; + + let mut snippet = SnippetData::new(cm.clone(), Some(rbrace_span)); + snippet.push(rbrace_span, false, None); + let lines = snippet.render_lines(); + let text: String = make_string(&lines); + println!("r#\"\n{}\"", text); + assert_eq!(text, &r#" + --> foo.rs:11:2 +11 |> } + |> - +"#[1..]); +}