// 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,
|> ----- 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..]);
+}