Consolidate codemap tests and fix more errors for travis
This commit is contained in:
parent
51deb4fedb
commit
f2fe204dcc
@ -1421,12 +1421,11 @@ mod tests {
|
||||
use middle::cstore::DummyCrateStore;
|
||||
use session::config::{build_configuration, build_session_options};
|
||||
use session::build_session;
|
||||
|
||||
use errors;
|
||||
use std::rc::Rc;
|
||||
use getopts::{getopts, OptGroup};
|
||||
use syntax::attr;
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::diagnostics;
|
||||
|
||||
fn optgroups() -> Vec<OptGroup> {
|
||||
super::rustc_optgroups().into_iter()
|
||||
@ -1443,7 +1442,7 @@ mod tests {
|
||||
Ok(m) => m,
|
||||
Err(f) => panic!("test_switch_implies_cfg_test: {}", f)
|
||||
};
|
||||
let registry = diagnostics::registry::Registry::new(&[]);
|
||||
let registry = errors::registry::Registry::new(&[]);
|
||||
let sessopts = build_session_options(matches);
|
||||
let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
|
||||
let cfg = build_configuration(&sess);
|
||||
@ -1463,7 +1462,7 @@ mod tests {
|
||||
panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
|
||||
}
|
||||
};
|
||||
let registry = diagnostics::registry::Registry::new(&[]);
|
||||
let registry = errors::registry::Registry::new(&[]);
|
||||
let sessopts = build_session_options(matches);
|
||||
let sess = build_session(sessopts, &dep_graph, None, registry,
|
||||
Rc::new(DummyCrateStore));
|
||||
@ -1480,7 +1479,7 @@ mod tests {
|
||||
let matches = getopts(&[
|
||||
"-Awarnings".to_string()
|
||||
], &optgroups()).unwrap();
|
||||
let registry = diagnostics::registry::Registry::new(&[]);
|
||||
let registry = errors::registry::Registry::new(&[]);
|
||||
let sessopts = build_session_options(&matches);
|
||||
let sess = build_session(sessopts, &dep_graph, None, registry,
|
||||
Rc::new(DummyCrateStore));
|
||||
@ -1492,7 +1491,7 @@ mod tests {
|
||||
"-Awarnings".to_string(),
|
||||
"-Dwarnings".to_string()
|
||||
], &optgroups()).unwrap();
|
||||
let registry = diagnostics::registry::Registry::new(&[]);
|
||||
let registry = errors::registry::Registry::new(&[]);
|
||||
let sessopts = build_session_options(&matches);
|
||||
let sess = build_session(sessopts, &dep_graph, None, registry,
|
||||
Rc::new(DummyCrateStore));
|
||||
@ -1503,7 +1502,7 @@ mod tests {
|
||||
let matches = getopts(&[
|
||||
"-Adead_code".to_string()
|
||||
], &optgroups()).unwrap();
|
||||
let registry = diagnostics::registry::Registry::new(&[]);
|
||||
let registry = errors::registry::Registry::new(&[]);
|
||||
let sessopts = build_session_options(&matches);
|
||||
let sess = build_session(sessopts, &dep_graph, None, registry,
|
||||
Rc::new(DummyCrateStore));
|
||||
|
@ -358,7 +358,7 @@ impl EmitterWriter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn highlight_lines(&mut self,
|
||||
pub fn highlight_lines(&mut self,
|
||||
msp: &MultiSpan,
|
||||
lvl: Level)
|
||||
-> io::Result<()>
|
||||
@ -619,256 +619,3 @@ impl Write for Destination {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use errors::{Level, CodeSuggestion};
|
||||
use super::EmitterWriter;
|
||||
use codemap::CodeMap;
|
||||
use syntax_pos::{mk_sp, Span, MultiSpan, BytePos, NO_EXPANSION};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{self, Write};
|
||||
use std::str::from_utf8;
|
||||
use std::rc::Rc;
|
||||
|
||||
struct Sink(Arc<Mutex<Vec<u8>>>);
|
||||
impl Write for Sink {
|
||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
Write::write(&mut *self.0.lock().unwrap(), data)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
/// Given a string like " ^~~~~~~~~~~~ ", produces a span
|
||||
/// coverting that range. The idea is that the string has the same
|
||||
/// length as the input, and we uncover the byte positions. Note
|
||||
/// that this can span lines and so on.
|
||||
fn span_from_selection(input: &str, selection: &str) -> Span {
|
||||
assert_eq!(input.len(), selection.len());
|
||||
let left_index = selection.find('~').unwrap() as u32;
|
||||
let right_index = selection.rfind('~').map(|x|x as u32).unwrap_or(left_index);
|
||||
Span { lo: BytePos(left_index), hi: BytePos(right_index + 1), expn_id: NO_EXPANSION }
|
||||
}
|
||||
|
||||
// Diagnostic doesn't align properly in span where line number increases by one digit
|
||||
#[test]
|
||||
fn test_hilight_suggestion_issue_11715() {
|
||||
let data = Arc::new(Mutex::new(Vec::new()));
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
|
||||
let content = "abcdefg
|
||||
koksi
|
||||
line3
|
||||
line4
|
||||
cinq
|
||||
line6
|
||||
line7
|
||||
line8
|
||||
line9
|
||||
line10
|
||||
e-lä-vän
|
||||
tolv
|
||||
dreizehn
|
||||
";
|
||||
let file = cm.new_filemap_and_lines("dummy.txt", None, content);
|
||||
let start = file.lines.borrow()[10];
|
||||
let end = file.lines.borrow()[11];
|
||||
let sp = mk_sp(start, end);
|
||||
let lvl = Level::Error;
|
||||
println!("highlight_lines");
|
||||
ew.highlight_lines(&sp.into(), lvl).unwrap();
|
||||
println!("done");
|
||||
let vec = data.lock().unwrap().clone();
|
||||
let vec: &[u8] = &vec;
|
||||
let str = from_utf8(vec).unwrap();
|
||||
println!("r#\"\n{}\"#", str);
|
||||
assert_eq!(str, &r#"
|
||||
--> dummy.txt:11:1
|
||||
|>
|
||||
11 |> e-lä-vän
|
||||
|> ^
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_span_splice() {
|
||||
// Test that a `MultiSpan` containing a single span splices a substition correctly
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
|
||||
let selection = " \n ~~\n~~~\n~~~~~ \n \n";
|
||||
cm.new_filemap_and_lines("blork.rs", None, inputtext);
|
||||
let sp = span_from_selection(inputtext, selection);
|
||||
let msp: MultiSpan = sp.into();
|
||||
|
||||
// check that we are extracting the text we thought we were extracting
|
||||
assert_eq!(&cm.span_to_snippet(sp).unwrap(), "BB\nCCC\nDDDDD");
|
||||
|
||||
let substitute = "ZZZZZZ".to_owned();
|
||||
let expected = "bbbbZZZZZZddddd";
|
||||
let suggest = CodeSuggestion {
|
||||
msp: msp,
|
||||
substitutes: vec![substitute],
|
||||
};
|
||||
assert_eq!(suggest.splice_lines(&cm), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_span_splice() {
|
||||
// Test that a `MultiSpan` containing multiple spans splices a substition correctly
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
|
||||
let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order
|
||||
let selection2 = " \n ~~\n~~~\n~~~~~ \n \n";
|
||||
cm.new_filemap_and_lines("blork.rs", None, inputtext);
|
||||
let sp1 = span_from_selection(inputtext, selection1);
|
||||
let sp2 = span_from_selection(inputtext, selection2);
|
||||
let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]);
|
||||
|
||||
let expected = "bbbbZZZZZZddddd\neXYZe";
|
||||
let suggest = CodeSuggestion {
|
||||
msp: msp,
|
||||
substitutes: vec!["ZZZZZZ".to_owned(),
|
||||
"XYZ".to_owned()]
|
||||
};
|
||||
|
||||
assert_eq!(suggest.splice_lines(&cm), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multispan_highlight() {
|
||||
let data = Arc::new(Mutex::new(Vec::new()));
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
|
||||
|
||||
let inp = "_____aaaaaa____bbbbbb__cccccdd_";
|
||||
let sp1 = " ~~~~~~ ";
|
||||
let sp2 = " ~~~~~~ ";
|
||||
let sp3 = " ~~~~~ ";
|
||||
let sp4 = " ~~~~ ";
|
||||
let sp34 = " ~~~~~~~ ";
|
||||
|
||||
let expect_start = &r#"
|
||||
--> dummy.txt:1:6
|
||||
|>
|
||||
1 |> _____aaaaaa____bbbbbb__cccccdd_
|
||||
|> ^^^^^^ ^^^^^^ ^^^^^^^
|
||||
"#[1..];
|
||||
|
||||
let span = |sp, expected| {
|
||||
let sp = span_from_selection(inp, sp);
|
||||
assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected);
|
||||
sp
|
||||
};
|
||||
cm.new_filemap_and_lines("dummy.txt", None, inp);
|
||||
let sp1 = span(sp1, "aaaaaa");
|
||||
let sp2 = span(sp2, "bbbbbb");
|
||||
let sp3 = span(sp3, "ccccc");
|
||||
let sp4 = span(sp4, "ccdd");
|
||||
let sp34 = span(sp34, "cccccdd");
|
||||
|
||||
let spans = vec![sp1, sp2, sp3, sp4];
|
||||
|
||||
let test = |expected, highlight: &mut FnMut()| {
|
||||
data.lock().unwrap().clear();
|
||||
highlight();
|
||||
let vec = data.lock().unwrap().clone();
|
||||
let actual = from_utf8(&vec[..]).unwrap();
|
||||
println!("actual=\n{}", actual);
|
||||
assert_eq!(actual, expected);
|
||||
};
|
||||
|
||||
let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]);
|
||||
test(expect_start, &mut || {
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
test(expect_start, &mut || {
|
||||
let msp = MultiSpan::from_spans(spans.clone());
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_huge_multispan_highlight() {
|
||||
let data = Arc::new(Mutex::new(Vec::new()));
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
|
||||
|
||||
let inp = "aaaaa\n\
|
||||
aaaaa\n\
|
||||
aaaaa\n\
|
||||
bbbbb\n\
|
||||
ccccc\n\
|
||||
xxxxx\n\
|
||||
yyyyy\n\
|
||||
_____\n\
|
||||
ddd__eee_\n\
|
||||
elided\n\
|
||||
__f_gg";
|
||||
let file = cm.new_filemap_and_lines("dummy.txt", None, inp);
|
||||
|
||||
let span = |lo, hi, (off_lo, off_hi)| {
|
||||
let lines = file.lines.borrow();
|
||||
let (mut lo, mut hi): (BytePos, BytePos) = (lines[lo], lines[hi]);
|
||||
lo.0 += off_lo;
|
||||
hi.0 += off_hi;
|
||||
mk_sp(lo, hi)
|
||||
};
|
||||
let sp0 = span(4, 6, (0, 5));
|
||||
let sp1 = span(0, 6, (0, 5));
|
||||
let sp2 = span(8, 8, (0, 3));
|
||||
let sp3 = span(8, 8, (5, 8));
|
||||
let sp4 = span(10, 10, (2, 3));
|
||||
let sp5 = span(10, 10, (4, 6));
|
||||
|
||||
let expect0 = &r#"
|
||||
--> dummy.txt:5:1
|
||||
|>
|
||||
5 |> ccccc
|
||||
|> ^
|
||||
...
|
||||
9 |> ddd__eee_
|
||||
|> ^^^ ^^^
|
||||
10 |> elided
|
||||
11 |> __f_gg
|
||||
|> ^ ^^
|
||||
"#[1..];
|
||||
|
||||
let expect = &r#"
|
||||
--> dummy.txt:1:1
|
||||
|>
|
||||
1 |> aaaaa
|
||||
|> ^
|
||||
...
|
||||
9 |> ddd__eee_
|
||||
|> ^^^ ^^^
|
||||
10 |> elided
|
||||
11 |> __f_gg
|
||||
|> ^ ^^
|
||||
"#[1..];
|
||||
|
||||
macro_rules! test {
|
||||
($expected: expr, $highlight: expr) => ({
|
||||
data.lock().unwrap().clear();
|
||||
$highlight();
|
||||
let vec = data.lock().unwrap().clone();
|
||||
let actual = from_utf8(&vec[..]).unwrap();
|
||||
println!("actual:");
|
||||
println!("{}", actual);
|
||||
println!("expected:");
|
||||
println!("{}", $expected);
|
||||
assert_eq!(&actual[..], &$expected[..]);
|
||||
});
|
||||
}
|
||||
|
||||
let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]);
|
||||
let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]);
|
||||
|
||||
test!(expect0, || {
|
||||
diag.highlight_lines(&msp0, Level::Error).unwrap();
|
||||
});
|
||||
test!(expect, || {
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,6 @@ use std::cmp;
|
||||
use std::rc::Rc;
|
||||
use std::mem;
|
||||
|
||||
mod test;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SnippetData {
|
||||
codemap: Rc<CodeMapper>,
|
||||
|
@ -1,598 +0,0 @@
|
||||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Code for testing annotated snippets.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use codemap::{CodeMap};
|
||||
use syntax_pos::{NO_EXPANSION, Span, FileMap, BytePos};
|
||||
use std::rc::Rc;
|
||||
use super::{RenderedLine, SnippetData};
|
||||
|
||||
/// Returns the span corresponding to the `n`th occurrence of
|
||||
/// `substring` in `source_text`.
|
||||
trait CodeMapExtension {
|
||||
fn span_substr(&self,
|
||||
file: &Rc<FileMap>,
|
||||
source_text: &str,
|
||||
substring: &str,
|
||||
n: usize)
|
||||
-> Span;
|
||||
}
|
||||
|
||||
impl CodeMapExtension for CodeMap {
|
||||
fn span_substr(&self,
|
||||
file: &Rc<FileMap>,
|
||||
source_text: &str,
|
||||
substring: &str,
|
||||
n: usize)
|
||||
-> Span
|
||||
{
|
||||
println!("span_substr(file={:?}/{:?}, substring={:?}, n={})",
|
||||
file.name, file.start_pos, substring, n);
|
||||
let mut i = 0;
|
||||
let mut hi = 0;
|
||||
loop {
|
||||
let offset = source_text[hi..].find(substring).unwrap_or_else(|| {
|
||||
panic!("source_text `{}` does not have {} occurrences of `{}`, only {}",
|
||||
source_text, n, substring, i);
|
||||
});
|
||||
let lo = hi + offset;
|
||||
hi = lo + substring.len();
|
||||
if i == n {
|
||||
let span = Span {
|
||||
lo: BytePos(lo as u32 + file.start_pos.0),
|
||||
hi: BytePos(hi as u32 + file.start_pos.0),
|
||||
expn_id: NO_EXPANSION,
|
||||
};
|
||||
assert_eq!(&self.span_to_snippet(span).unwrap()[..],
|
||||
substring);
|
||||
return span;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn splice(start: Span, end: Span) -> Span {
|
||||
Span {
|
||||
lo: start.lo,
|
||||
hi: end.hi,
|
||||
expn_id: NO_EXPANSION,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_string(lines: &[RenderedLine]) -> String {
|
||||
lines.iter()
|
||||
.flat_map(|rl| {
|
||||
rl.text.iter()
|
||||
.map(|s| &s.text[..])
|
||||
.chain(Some("\n"))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab() {
|
||||
let file_text = "
|
||||
fn foo() {
|
||||
\tbar;
|
||||
}
|
||||
";
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_bar = cm.span_substr(&foo, file_text, "bar", 0);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, Some(span_bar));
|
||||
snippet.push(span_bar, true, None);
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
let text = make_string(&lines);
|
||||
assert_eq!(&text[..], &"
|
||||
--> foo.rs:3:2
|
||||
|>
|
||||
3 |> \tbar;
|
||||
|> \t^^^
|
||||
"[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_line() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
vec.push(vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
|
||||
let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
|
||||
let span_semi = cm.span_substr(&foo, file_text, ";", 0);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
|
||||
snippet.push(span_vec1, false, Some(format!("error occurs here")));
|
||||
snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=\n{}", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- --- - previous borrow ends here
|
||||
|> | |
|
||||
|> | error occurs here
|
||||
|> previous borrow of `vec` occurs here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_files() {
|
||||
let file_text_foo = r#"
|
||||
fn foo() {
|
||||
vec.push(vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let file_text_bar = r#"
|
||||
fn bar() {
|
||||
// these blank links here
|
||||
// serve to ensure that the line numbers
|
||||
// from bar.rs
|
||||
// require more digits
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
vec.push();
|
||||
|
||||
// this line will get elided
|
||||
|
||||
vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo);
|
||||
let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0);
|
||||
let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1);
|
||||
let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0);
|
||||
|
||||
let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar);
|
||||
let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0);
|
||||
let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1);
|
||||
let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, Some(span_foo_vec1));
|
||||
snippet.push(span_foo_vec0, false, Some(format!("a")));
|
||||
snippet.push(span_foo_vec1, true, Some(format!("b")));
|
||||
snippet.push(span_foo_semi, false, Some(format!("c")));
|
||||
snippet.push(span_bar_vec0, false, Some(format!("d")));
|
||||
snippet.push(span_bar_vec1, false, Some(format!("e")));
|
||||
snippet.push(span_bar_semi, false, Some(format!("f")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=\n{}", text);
|
||||
|
||||
// Note that the `|>` remain aligned across both files:
|
||||
assert_eq!(&text[..], &r#"
|
||||
--> foo.rs:3:14
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- ^^^ - c
|
||||
|> | |
|
||||
|> | b
|
||||
|> a
|
||||
::: bar.rs
|
||||
|>
|
||||
17 |> vec.push();
|
||||
|> --- - f
|
||||
|> |
|
||||
|> d
|
||||
...
|
||||
21 |> vec.pop().unwrap());
|
||||
|> --- e
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_line() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
let name = find_id(&data, 22).unwrap();
|
||||
|
||||
// Add one more item we forgot to the vector. Silly us.
|
||||
data.push(Data { name: format!("Hera"), id: 66 });
|
||||
|
||||
// Print everything out.
|
||||
println!("Name: {:?}", name);
|
||||
println!("Data: {:?}", data);
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_data0 = cm.span_substr(&foo, file_text, "data", 0);
|
||||
let span_data1 = cm.span_substr(&foo, file_text, "data", 1);
|
||||
let span_rbrace = cm.span_substr(&foo, file_text, "}", 3);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span_data0, false, Some(format!("immutable borrow begins here")));
|
||||
snippet.push(span_data1, false, Some(format!("mutable borrow occurs here")));
|
||||
snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=\n{}", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let name = find_id(&data, 22).unwrap();
|
||||
|> ---- immutable borrow begins here
|
||||
...
|
||||
6 |> data.push(Data { name: format!("Hera"), id: 66 });
|
||||
|> ---- mutable borrow occurs here
|
||||
...
|
||||
11 |> }
|
||||
|> - immutable borrow ends here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlapping() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
vec.push(vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span0 = cm.span_substr(&foo, file_text, "vec.push", 0);
|
||||
let span1 = cm.span_substr(&foo, file_text, "vec", 0);
|
||||
let span2 = cm.span_substr(&foo, file_text, "ec.push", 0);
|
||||
let span3 = cm.span_substr(&foo, file_text, "unwrap", 0);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span0, false, Some(format!("A")));
|
||||
snippet.push(span1, false, Some(format!("B")));
|
||||
snippet.push(span2, false, Some(format!("C")));
|
||||
snippet.push(span3, false, Some(format!("D")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> -------- ------ D
|
||||
|> ||
|
||||
|> |C
|
||||
|> A
|
||||
|> B
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_line_out_of_order() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
vec.push(vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
|
||||
let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
|
||||
let span_semi = cm.span_substr(&foo, file_text, ";", 0);
|
||||
|
||||
// intentionally don't push the snippets left to right
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span_vec1, false, Some(format!("error occurs here")));
|
||||
snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
|
||||
snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- --- - previous borrow ends here
|
||||
|> | |
|
||||
|> | error occurs here
|
||||
|> previous borrow of `vec` occurs here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn elide_unnecessary_lines() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
let mut vec = vec![0, 1, 2];
|
||||
let mut vec2 = vec;
|
||||
vec2.push(3);
|
||||
vec2.push(4);
|
||||
vec2.push(5);
|
||||
vec2.push(6);
|
||||
vec.push(7);
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3);
|
||||
let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \
|
||||
has type `collections::vec::Vec<i32>`")));
|
||||
snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
let text: String = make_string(&lines);
|
||||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
4 |> let mut vec2 = vec;
|
||||
|> --- `vec` moved here because it has type `collections::vec::Vec<i32>`
|
||||
...
|
||||
9 |> vec.push(7);
|
||||
|> --- use of moved value: `vec`
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spans_without_labels() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
let mut vec = vec![0, 1, 2];
|
||||
let mut vec2 = vec;
|
||||
vec2.push(3);
|
||||
vec2.push(4);
|
||||
vec2.push(5);
|
||||
vec2.push(6);
|
||||
vec.push(7);
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
for i in 0..4 {
|
||||
let span_veci = cm.span_substr(&foo, file_text, "vec", i);
|
||||
snippet.push(span_veci, false, None);
|
||||
}
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
let text: String = make_string(&lines);
|
||||
println!("text=&r#\"\n{}\n\"#[1..]", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let mut vec = vec![0, 1, 2];
|
||||
|> --- ---
|
||||
4 |> let mut vec2 = vec;
|
||||
|> --- ---
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_long_selection() {
|
||||
let file_text = r#"
|
||||
impl SomeTrait for () {
|
||||
fn foo(x: u32) {
|
||||
// impl 1
|
||||
// impl 2
|
||||
// impl 3
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
let fn_span = cm.span_substr(&foo, file_text, "fn", 0);
|
||||
let rbrace_span = cm.span_substr(&foo, file_text, "}", 0);
|
||||
snippet.push(splice(fn_span, 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
|
||||
|>
|
||||
3 |> fn foo(x: u32) {
|
||||
|> -
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_overlap_label() {
|
||||
// Test that we don't put `x_span` to the right of its highlight,
|
||||
// since there is another highlight that overlaps it.
|
||||
|
||||
let file_text = r#"
|
||||
fn foo(x: u32) {
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0);
|
||||
let x_span = cm.span_substr(&foo, file_text, "x", 0);
|
||||
snippet.push(fn_span, false, Some(format!("fn_span")));
|
||||
snippet.push(x_span, false, Some(format!("x_span")));
|
||||
let lines = snippet.render_lines();
|
||||
let text: String = make_string(&lines);
|
||||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
2 |> fn foo(x: u32) {
|
||||
|> --------------
|
||||
|> | |
|
||||
|> | x_span
|
||||
|> fn_span
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_overlap_label2() {
|
||||
// Test that we don't put `x_span` to the right of its highlight,
|
||||
// since there is another highlight that overlaps it. In this
|
||||
// case, the overlap is only at the beginning, but it's still
|
||||
// better to show the beginning more clearly.
|
||||
|
||||
let file_text = r#"
|
||||
fn foo(x: u32) {
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0);
|
||||
let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0);
|
||||
snippet.push(fn_span, false, Some(format!("fn_span")));
|
||||
snippet.push(x_span, false, Some(format!("x_span")));
|
||||
let lines = snippet.render_lines();
|
||||
let text: String = make_string(&lines);
|
||||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
2 |> fn foo(x: u32) {
|
||||
|> --------------
|
||||
|> | |
|
||||
|> | x_span
|
||||
|> fn_span
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_overlap_label3() {
|
||||
// Test that we don't put `x_span` to the right of its highlight,
|
||||
// since there is another highlight that overlaps it. In this
|
||||
// case, the overlap is only at the beginning, but it's still
|
||||
// better to show the beginning more clearly.
|
||||
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
let closure = || {
|
||||
inner
|
||||
};
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
|
||||
let closure_span = {
|
||||
let closure_start_span = cm.span_substr(&foo, file_text, "||", 0);
|
||||
let closure_end_span = cm.span_substr(&foo, file_text, "}", 0);
|
||||
splice(closure_start_span, closure_end_span)
|
||||
};
|
||||
|
||||
let inner_span = cm.span_substr(&foo, file_text, "inner", 0);
|
||||
|
||||
snippet.push(closure_span, false, Some(format!("foo")));
|
||||
snippet.push(inner_span, false, Some(format!("bar")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
let text: String = make_string(&lines);
|
||||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let closure = || {
|
||||
|> - foo
|
||||
4 |> inner
|
||||
|> ----- 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", None, 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..]);
|
||||
}
|
@ -828,6 +828,12 @@ impl CodeMapper for CodeMap {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use syntax_pos::*;
|
||||
use errors::{Level, CodeSuggestion};
|
||||
use errors::emitter::EmitterWriter;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::io::{self, Write};
|
||||
use std::str::from_utf8;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn t1 () {
|
||||
@ -1150,4 +1156,233 @@ r"blork2.rs:2:1: 2:12
|
||||
";
|
||||
assert_eq!(sstr, res_str);
|
||||
}
|
||||
|
||||
struct Sink(Arc<Mutex<Vec<u8>>>);
|
||||
impl Write for Sink {
|
||||
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
|
||||
Write::write(&mut *self.0.lock().unwrap(), data)
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||
}
|
||||
|
||||
// Diagnostic doesn't align properly in span where line number increases by one digit
|
||||
#[test]
|
||||
fn test_hilight_suggestion_issue_11715() {
|
||||
let data = Arc::new(Mutex::new(Vec::new()));
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let mut ew = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
|
||||
let content = "abcdefg
|
||||
koksi
|
||||
line3
|
||||
line4
|
||||
cinq
|
||||
line6
|
||||
line7
|
||||
line8
|
||||
line9
|
||||
line10
|
||||
e-lä-vän
|
||||
tolv
|
||||
dreizehn
|
||||
";
|
||||
let file = cm.new_filemap_and_lines("dummy.txt", None, content);
|
||||
let start = file.lines.borrow()[10];
|
||||
let end = file.lines.borrow()[11];
|
||||
let sp = mk_sp(start, end);
|
||||
let lvl = Level::Error;
|
||||
println!("highlight_lines");
|
||||
ew.highlight_lines(&sp.into(), lvl).unwrap();
|
||||
println!("done");
|
||||
let vec = data.lock().unwrap().clone();
|
||||
let vec: &[u8] = &vec;
|
||||
let str = from_utf8(vec).unwrap();
|
||||
println!("r#\"\n{}\"#", str);
|
||||
assert_eq!(str, &r#"
|
||||
--> dummy.txt:11:1
|
||||
|>
|
||||
11 |> e-lä-vän
|
||||
|> ^
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_single_span_splice() {
|
||||
// Test that a `MultiSpan` containing a single span splices a substition correctly
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
|
||||
let selection = " \n ~~\n~~~\n~~~~~ \n \n";
|
||||
cm.new_filemap_and_lines("blork.rs", None, inputtext);
|
||||
let sp = span_from_selection(inputtext, selection);
|
||||
let msp: MultiSpan = sp.into();
|
||||
|
||||
// check that we are extracting the text we thought we were extracting
|
||||
assert_eq!(&cm.span_to_snippet(sp).unwrap(), "BB\nCCC\nDDDDD");
|
||||
|
||||
let substitute = "ZZZZZZ".to_owned();
|
||||
let expected = "bbbbZZZZZZddddd";
|
||||
let suggest = CodeSuggestion {
|
||||
msp: msp,
|
||||
substitutes: vec![substitute],
|
||||
};
|
||||
assert_eq!(suggest.splice_lines(&cm), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_span_splice() {
|
||||
// Test that a `MultiSpan` containing multiple spans splices a substition correctly
|
||||
let cm = CodeMap::new();
|
||||
let inputtext = "aaaaa\nbbbbBB\nCCC\nDDDDDddddd\neee\n";
|
||||
let selection1 = " \n \n \n \n ~ \n"; // intentionally out of order
|
||||
let selection2 = " \n ~~\n~~~\n~~~~~ \n \n";
|
||||
cm.new_filemap_and_lines("blork.rs", None, inputtext);
|
||||
let sp1 = span_from_selection(inputtext, selection1);
|
||||
let sp2 = span_from_selection(inputtext, selection2);
|
||||
let msp: MultiSpan = MultiSpan::from_spans(vec![sp1, sp2]);
|
||||
|
||||
let expected = "bbbbZZZZZZddddd\neXYZe";
|
||||
let suggest = CodeSuggestion {
|
||||
msp: msp,
|
||||
substitutes: vec!["ZZZZZZ".to_owned(),
|
||||
"XYZ".to_owned()]
|
||||
};
|
||||
|
||||
assert_eq!(suggest.splice_lines(&cm), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multispan_highlight() {
|
||||
let data = Arc::new(Mutex::new(Vec::new()));
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
|
||||
|
||||
let inp = "_____aaaaaa____bbbbbb__cccccdd_";
|
||||
let sp1 = " ~~~~~~ ";
|
||||
let sp2 = " ~~~~~~ ";
|
||||
let sp3 = " ~~~~~ ";
|
||||
let sp4 = " ~~~~ ";
|
||||
let sp34 = " ~~~~~~~ ";
|
||||
|
||||
let expect_start = &r#"
|
||||
--> dummy.txt:1:6
|
||||
|>
|
||||
1 |> _____aaaaaa____bbbbbb__cccccdd_
|
||||
|> ^^^^^^ ^^^^^^ ^^^^^^^
|
||||
"#[1..];
|
||||
|
||||
let span = |sp, expected| {
|
||||
let sp = span_from_selection(inp, sp);
|
||||
assert_eq!(&cm.span_to_snippet(sp).unwrap(), expected);
|
||||
sp
|
||||
};
|
||||
cm.new_filemap_and_lines("dummy.txt", None, inp);
|
||||
let sp1 = span(sp1, "aaaaaa");
|
||||
let sp2 = span(sp2, "bbbbbb");
|
||||
let sp3 = span(sp3, "ccccc");
|
||||
let sp4 = span(sp4, "ccdd");
|
||||
let sp34 = span(sp34, "cccccdd");
|
||||
|
||||
let spans = vec![sp1, sp2, sp3, sp4];
|
||||
|
||||
let test = |expected, highlight: &mut FnMut()| {
|
||||
data.lock().unwrap().clear();
|
||||
highlight();
|
||||
let vec = data.lock().unwrap().clone();
|
||||
let actual = from_utf8(&vec[..]).unwrap();
|
||||
println!("actual=\n{}", actual);
|
||||
assert_eq!(actual, expected);
|
||||
};
|
||||
|
||||
let msp = MultiSpan::from_spans(vec![sp1, sp2, sp34]);
|
||||
test(expect_start, &mut || {
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
test(expect_start, &mut || {
|
||||
let msp = MultiSpan::from_spans(spans.clone());
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_huge_multispan_highlight() {
|
||||
let data = Arc::new(Mutex::new(Vec::new()));
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let mut diag = EmitterWriter::new(Box::new(Sink(data.clone())), None, cm.clone());
|
||||
|
||||
let inp = "aaaaa\n\
|
||||
aaaaa\n\
|
||||
aaaaa\n\
|
||||
bbbbb\n\
|
||||
ccccc\n\
|
||||
xxxxx\n\
|
||||
yyyyy\n\
|
||||
_____\n\
|
||||
ddd__eee_\n\
|
||||
elided\n\
|
||||
__f_gg";
|
||||
let file = cm.new_filemap_and_lines("dummy.txt", None, inp);
|
||||
|
||||
let span = |lo, hi, (off_lo, off_hi)| {
|
||||
let lines = file.lines.borrow();
|
||||
let (mut lo, mut hi): (BytePos, BytePos) = (lines[lo], lines[hi]);
|
||||
lo.0 += off_lo;
|
||||
hi.0 += off_hi;
|
||||
mk_sp(lo, hi)
|
||||
};
|
||||
let sp0 = span(4, 6, (0, 5));
|
||||
let sp1 = span(0, 6, (0, 5));
|
||||
let sp2 = span(8, 8, (0, 3));
|
||||
let sp3 = span(8, 8, (5, 8));
|
||||
let sp4 = span(10, 10, (2, 3));
|
||||
let sp5 = span(10, 10, (4, 6));
|
||||
|
||||
let expect0 = &r#"
|
||||
--> dummy.txt:5:1
|
||||
|>
|
||||
5 |> ccccc
|
||||
|> ^
|
||||
...
|
||||
9 |> ddd__eee_
|
||||
|> ^^^ ^^^
|
||||
10 |> elided
|
||||
11 |> __f_gg
|
||||
|> ^ ^^
|
||||
"#[1..];
|
||||
|
||||
let expect = &r#"
|
||||
--> dummy.txt:1:1
|
||||
|>
|
||||
1 |> aaaaa
|
||||
|> ^
|
||||
...
|
||||
9 |> ddd__eee_
|
||||
|> ^^^ ^^^
|
||||
10 |> elided
|
||||
11 |> __f_gg
|
||||
|> ^ ^^
|
||||
"#[1..];
|
||||
|
||||
macro_rules! test {
|
||||
($expected: expr, $highlight: expr) => ({
|
||||
data.lock().unwrap().clear();
|
||||
$highlight();
|
||||
let vec = data.lock().unwrap().clone();
|
||||
let actual = from_utf8(&vec[..]).unwrap();
|
||||
println!("actual:");
|
||||
println!("{}", actual);
|
||||
println!("expected:");
|
||||
println!("{}", $expected);
|
||||
assert_eq!(&actual[..], &$expected[..]);
|
||||
});
|
||||
}
|
||||
|
||||
let msp0 = MultiSpan::from_spans(vec![sp0, sp2, sp3, sp4, sp5]);
|
||||
let msp = MultiSpan::from_spans(vec![sp1, sp2, sp3, sp4, sp5]);
|
||||
|
||||
test!(expect0, || {
|
||||
diag.highlight_lines(&msp0, Level::Error).unwrap();
|
||||
});
|
||||
test!(expect, || {
|
||||
diag.highlight_lines(&msp, Level::Error).unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use self::HasTestSignature::*;
|
||||
|
||||
use std::iter;
|
||||
@ -20,9 +21,12 @@ use std::mem;
|
||||
use std::vec;
|
||||
use attr::AttrMetaMethods;
|
||||
use attr;
|
||||
use syntax_pos::{self, DUMMY_SP, Span};
|
||||
use codemap::{self, ExpnInfo, NameAndSpan, MacroAttribute};
|
||||
use syntax_pos::{self, DUMMY_SP, NO_EXPANSION, Span, FileMap, BytePos};
|
||||
use std::rc::Rc;
|
||||
|
||||
use codemap::{self, CodeMap, ExpnInfo, NameAndSpan, MacroAttribute};
|
||||
use errors;
|
||||
use errors::snippet::{RenderedLine, SnippetData};
|
||||
use config;
|
||||
use entry::{self, EntryPointType};
|
||||
use ext::base::{ExtCtxt, DummyMacroLoader};
|
||||
@ -688,3 +692,583 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> P<ast::Expr> {
|
||||
vec![field("desc", desc_expr),
|
||||
field("testfn", testfn_expr)])
|
||||
}
|
||||
|
||||
/// Returns the span corresponding to the `n`th occurrence of
|
||||
/// `substring` in `source_text`.
|
||||
trait CodeMapExtension {
|
||||
fn span_substr(&self,
|
||||
file: &Rc<FileMap>,
|
||||
source_text: &str,
|
||||
substring: &str,
|
||||
n: usize)
|
||||
-> Span;
|
||||
}
|
||||
|
||||
impl CodeMapExtension for CodeMap {
|
||||
fn span_substr(&self,
|
||||
file: &Rc<FileMap>,
|
||||
source_text: &str,
|
||||
substring: &str,
|
||||
n: usize)
|
||||
-> Span
|
||||
{
|
||||
println!("span_substr(file={:?}/{:?}, substring={:?}, n={})",
|
||||
file.name, file.start_pos, substring, n);
|
||||
let mut i = 0;
|
||||
let mut hi = 0;
|
||||
loop {
|
||||
let offset = source_text[hi..].find(substring).unwrap_or_else(|| {
|
||||
panic!("source_text `{}` does not have {} occurrences of `{}`, only {}",
|
||||
source_text, n, substring, i);
|
||||
});
|
||||
let lo = hi + offset;
|
||||
hi = lo + substring.len();
|
||||
if i == n {
|
||||
let span = Span {
|
||||
lo: BytePos(lo as u32 + file.start_pos.0),
|
||||
hi: BytePos(hi as u32 + file.start_pos.0),
|
||||
expn_id: NO_EXPANSION,
|
||||
};
|
||||
assert_eq!(&self.span_to_snippet(span).unwrap()[..],
|
||||
substring);
|
||||
return span;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn splice(start: Span, end: Span) -> Span {
|
||||
Span {
|
||||
lo: start.lo,
|
||||
hi: end.hi,
|
||||
expn_id: NO_EXPANSION,
|
||||
}
|
||||
}
|
||||
|
||||
fn make_string(lines: &[RenderedLine]) -> String {
|
||||
lines.iter()
|
||||
.flat_map(|rl| {
|
||||
rl.text.iter()
|
||||
.map(|s| &s.text[..])
|
||||
.chain(Some("\n"))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab() {
|
||||
let file_text = "
|
||||
fn foo() {
|
||||
\tbar;
|
||||
}
|
||||
";
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_bar = cm.span_substr(&foo, file_text, "bar", 0);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, Some(span_bar));
|
||||
snippet.push(span_bar, true, None);
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
let text = make_string(&lines);
|
||||
assert_eq!(&text[..], &"
|
||||
--> foo.rs:3:2
|
||||
|>
|
||||
3 |> \tbar;
|
||||
|> \t^^^
|
||||
"[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_line() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
vec.push(vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
|
||||
let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
|
||||
let span_semi = cm.span_substr(&foo, file_text, ";", 0);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
|
||||
snippet.push(span_vec1, false, Some(format!("error occurs here")));
|
||||
snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=\n{}", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- --- - previous borrow ends here
|
||||
|> | |
|
||||
|> | error occurs here
|
||||
|> previous borrow of `vec` occurs here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_files() {
|
||||
let file_text_foo = r#"
|
||||
fn foo() {
|
||||
vec.push(vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let file_text_bar = r#"
|
||||
fn bar() {
|
||||
// these blank links here
|
||||
// serve to ensure that the line numbers
|
||||
// from bar.rs
|
||||
// require more digits
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
vec.push();
|
||||
|
||||
// this line will get elided
|
||||
|
||||
vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo_map = cm.new_filemap_and_lines("foo.rs", None, file_text_foo);
|
||||
let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0);
|
||||
let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1);
|
||||
let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0);
|
||||
|
||||
let bar_map = cm.new_filemap_and_lines("bar.rs", None, file_text_bar);
|
||||
let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0);
|
||||
let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1);
|
||||
let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, Some(span_foo_vec1));
|
||||
snippet.push(span_foo_vec0, false, Some(format!("a")));
|
||||
snippet.push(span_foo_vec1, true, Some(format!("b")));
|
||||
snippet.push(span_foo_semi, false, Some(format!("c")));
|
||||
snippet.push(span_bar_vec0, false, Some(format!("d")));
|
||||
snippet.push(span_bar_vec1, false, Some(format!("e")));
|
||||
snippet.push(span_bar_semi, false, Some(format!("f")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=\n{}", text);
|
||||
|
||||
// Note that the `|>` remain aligned across both files:
|
||||
assert_eq!(&text[..], &r#"
|
||||
--> foo.rs:3:14
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- ^^^ - c
|
||||
|> | |
|
||||
|> | b
|
||||
|> a
|
||||
::: bar.rs
|
||||
|>
|
||||
17 |> vec.push();
|
||||
|> --- - f
|
||||
|> |
|
||||
|> d
|
||||
...
|
||||
21 |> vec.pop().unwrap());
|
||||
|> --- e
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_line() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
let name = find_id(&data, 22).unwrap();
|
||||
|
||||
// Add one more item we forgot to the vector. Silly us.
|
||||
data.push(Data { name: format!("Hera"), id: 66 });
|
||||
|
||||
// Print everything out.
|
||||
println!("Name: {:?}", name);
|
||||
println!("Data: {:?}", data);
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_data0 = cm.span_substr(&foo, file_text, "data", 0);
|
||||
let span_data1 = cm.span_substr(&foo, file_text, "data", 1);
|
||||
let span_rbrace = cm.span_substr(&foo, file_text, "}", 3);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span_data0, false, Some(format!("immutable borrow begins here")));
|
||||
snippet.push(span_data1, false, Some(format!("mutable borrow occurs here")));
|
||||
snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=\n{}", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let name = find_id(&data, 22).unwrap();
|
||||
|> ---- immutable borrow begins here
|
||||
...
|
||||
6 |> data.push(Data { name: format!("Hera"), id: 66 });
|
||||
|> ---- mutable borrow occurs here
|
||||
...
|
||||
11 |> }
|
||||
|> - immutable borrow ends here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlapping() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
vec.push(vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span0 = cm.span_substr(&foo, file_text, "vec.push", 0);
|
||||
let span1 = cm.span_substr(&foo, file_text, "vec", 0);
|
||||
let span2 = cm.span_substr(&foo, file_text, "ec.push", 0);
|
||||
let span3 = cm.span_substr(&foo, file_text, "unwrap", 0);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span0, false, Some(format!("A")));
|
||||
snippet.push(span1, false, Some(format!("B")));
|
||||
snippet.push(span2, false, Some(format!("C")));
|
||||
snippet.push(span3, false, Some(format!("D")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> -------- ------ D
|
||||
|> ||
|
||||
|> |C
|
||||
|> A
|
||||
|> B
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn one_line_out_of_order() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
vec.push(vec.pop().unwrap());
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
|
||||
let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
|
||||
let span_semi = cm.span_substr(&foo, file_text, ";", 0);
|
||||
|
||||
// intentionally don't push the snippets left to right
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span_vec1, false, Some(format!("error occurs here")));
|
||||
snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
|
||||
snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
let text: String = make_string(&lines);
|
||||
|
||||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> vec.push(vec.pop().unwrap());
|
||||
|> --- --- - previous borrow ends here
|
||||
|> | |
|
||||
|> | error occurs here
|
||||
|> previous borrow of `vec` occurs here
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn elide_unnecessary_lines() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
let mut vec = vec![0, 1, 2];
|
||||
let mut vec2 = vec;
|
||||
vec2.push(3);
|
||||
vec2.push(4);
|
||||
vec2.push(5);
|
||||
vec2.push(6);
|
||||
vec.push(7);
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3);
|
||||
let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8);
|
||||
|
||||
let mut snippet = SnippetData::new(cm, None);
|
||||
snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \
|
||||
has type `collections::vec::Vec<i32>`")));
|
||||
snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
println!("{:#?}", lines);
|
||||
let text: String = make_string(&lines);
|
||||
println!("text=r#\"\n{}\".trim_left()", text);
|
||||
assert_eq!(&text[..], &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
4 |> let mut vec2 = vec;
|
||||
|> --- `vec` moved here because it has type `collections::vec::Vec<i32>`
|
||||
...
|
||||
9 |> vec.push(7);
|
||||
|> --- use of moved value: `vec`
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn spans_without_labels() {
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
let mut vec = vec![0, 1, 2];
|
||||
let mut vec2 = vec;
|
||||
vec2.push(3);
|
||||
vec2.push(4);
|
||||
vec2.push(5);
|
||||
vec2.push(6);
|
||||
vec.push(7);
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
for i in 0..4 {
|
||||
let span_veci = cm.span_substr(&foo, file_text, "vec", i);
|
||||
snippet.push(span_veci, false, None);
|
||||
}
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
let text: String = make_string(&lines);
|
||||
println!("text=&r#\"\n{}\n\"#[1..]", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let mut vec = vec![0, 1, 2];
|
||||
|> --- ---
|
||||
4 |> let mut vec2 = vec;
|
||||
|> --- ---
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_long_selection() {
|
||||
let file_text = r#"
|
||||
impl SomeTrait for () {
|
||||
fn foo(x: u32) {
|
||||
// impl 1
|
||||
// impl 2
|
||||
// impl 3
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
let fn_span = cm.span_substr(&foo, file_text, "fn", 0);
|
||||
let rbrace_span = cm.span_substr(&foo, file_text, "}", 0);
|
||||
snippet.push(splice(fn_span, 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
|
||||
|>
|
||||
3 |> fn foo(x: u32) {
|
||||
|> -
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_overlap_label() {
|
||||
// Test that we don't put `x_span` to the right of its highlight,
|
||||
// since there is another highlight that overlaps it.
|
||||
|
||||
let file_text = r#"
|
||||
fn foo(x: u32) {
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0);
|
||||
let x_span = cm.span_substr(&foo, file_text, "x", 0);
|
||||
snippet.push(fn_span, false, Some(format!("fn_span")));
|
||||
snippet.push(x_span, false, Some(format!("x_span")));
|
||||
let lines = snippet.render_lines();
|
||||
let text: String = make_string(&lines);
|
||||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
2 |> fn foo(x: u32) {
|
||||
|> --------------
|
||||
|> | |
|
||||
|> | x_span
|
||||
|> fn_span
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_overlap_label2() {
|
||||
// Test that we don't put `x_span` to the right of its highlight,
|
||||
// since there is another highlight that overlaps it. In this
|
||||
// case, the overlap is only at the beginning, but it's still
|
||||
// better to show the beginning more clearly.
|
||||
|
||||
let file_text = r#"
|
||||
fn foo(x: u32) {
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0);
|
||||
let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0);
|
||||
snippet.push(fn_span, false, Some(format!("fn_span")));
|
||||
snippet.push(x_span, false, Some(format!("x_span")));
|
||||
let lines = snippet.render_lines();
|
||||
let text: String = make_string(&lines);
|
||||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
2 |> fn foo(x: u32) {
|
||||
|> --------------
|
||||
|> | |
|
||||
|> | x_span
|
||||
|> fn_span
|
||||
"#[1..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn span_overlap_label3() {
|
||||
// Test that we don't put `x_span` to the right of its highlight,
|
||||
// since there is another highlight that overlaps it. In this
|
||||
// case, the overlap is only at the beginning, but it's still
|
||||
// better to show the beginning more clearly.
|
||||
|
||||
let file_text = r#"
|
||||
fn foo() {
|
||||
let closure = || {
|
||||
inner
|
||||
};
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
let cm = Rc::new(CodeMap::new());
|
||||
let foo = cm.new_filemap_and_lines("foo.rs", None, file_text);
|
||||
|
||||
let mut snippet = SnippetData::new(cm.clone(), None);
|
||||
|
||||
let closure_span = {
|
||||
let closure_start_span = cm.span_substr(&foo, file_text, "||", 0);
|
||||
let closure_end_span = cm.span_substr(&foo, file_text, "}", 0);
|
||||
splice(closure_start_span, closure_end_span)
|
||||
};
|
||||
|
||||
let inner_span = cm.span_substr(&foo, file_text, "inner", 0);
|
||||
|
||||
snippet.push(closure_span, false, Some(format!("foo")));
|
||||
snippet.push(inner_span, false, Some(format!("bar")));
|
||||
|
||||
let lines = snippet.render_lines();
|
||||
let text: String = make_string(&lines);
|
||||
println!("r#\"\n{}\"", text);
|
||||
assert_eq!(text, &r#"
|
||||
::: foo.rs
|
||||
|>
|
||||
3 |> let closure = || {
|
||||
|> - foo
|
||||
4 |> inner
|
||||
|> ----- 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", None, 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..]);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user