1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // Code for testing annotated snippets.
15 use codemap::{BytePos, CodeMap, FileMap, NO_EXPANSION, Span};
17 use super::{RenderedLine, SnippetData};
19 /// Returns the span corresponding to the `n`th occurrence of
20 /// `substring` in `source_text`.
21 trait CodeMapExtension {
30 impl CodeMapExtension for CodeMap {
38 println!("span_substr(file={:?}/{:?}, substring={:?}, n={})",
39 file.name, file.start_pos, substring, n);
43 let offset = source_text[hi..].find(substring).unwrap_or_else(|| {
44 panic!("source_text `{}` does not have {} occurrences of `{}`, only {}",
45 source_text, n, substring, i);
48 hi = lo + substring.len();
51 lo: BytePos(lo as u32 + file.start_pos.0),
52 hi: BytePos(hi as u32 + file.start_pos.0),
53 expn_id: NO_EXPANSION,
55 assert_eq!(&self.span_to_snippet(span).unwrap()[..],
64 fn splice(start: Span, end: Span) -> Span {
68 expn_id: NO_EXPANSION,
72 fn make_string(lines: &[RenderedLine]) -> String {
90 let cm = Rc::new(CodeMap::new());
91 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
92 let span_bar = cm.span_substr(&foo, file_text, "bar", 0);
94 let mut snippet = SnippetData::new(cm, Some(span_bar));
95 snippet.push(span_bar, true, None);
97 let lines = snippet.render_lines();
98 let text = make_string(&lines);
99 assert_eq!(&text[..], &"
110 vec.push(vec.pop().unwrap());
114 let cm = Rc::new(CodeMap::new());
115 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
116 let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
117 let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
118 let span_semi = cm.span_substr(&foo, file_text, ";", 0);
120 let mut snippet = SnippetData::new(cm, None);
121 snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
122 snippet.push(span_vec1, false, Some(format!("error occurs here")));
123 snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
125 let lines = snippet.render_lines();
126 println!("{:#?}", lines);
128 let text: String = make_string(&lines);
130 println!("text=\n{}", text);
131 assert_eq!(&text[..], &r#"
133 3 |> vec.push(vec.pop().unwrap());
134 |> --- --- - previous borrow ends here
136 |> | error occurs here
137 |> previous borrow of `vec` occurs here
143 let file_text_foo = r#"
145 vec.push(vec.pop().unwrap());
149 let file_text_bar = r#"
151 // these blank links here
152 // serve to ensure that the line numbers
154 // require more digits
167 // this line will get elided
173 let cm = Rc::new(CodeMap::new());
174 let foo_map = cm.new_filemap_and_lines("foo.rs", file_text_foo);
175 let span_foo_vec0 = cm.span_substr(&foo_map, file_text_foo, "vec", 0);
176 let span_foo_vec1 = cm.span_substr(&foo_map, file_text_foo, "vec", 1);
177 let span_foo_semi = cm.span_substr(&foo_map, file_text_foo, ";", 0);
179 let bar_map = cm.new_filemap_and_lines("bar.rs", file_text_bar);
180 let span_bar_vec0 = cm.span_substr(&bar_map, file_text_bar, "vec", 0);
181 let span_bar_vec1 = cm.span_substr(&bar_map, file_text_bar, "vec", 1);
182 let span_bar_semi = cm.span_substr(&bar_map, file_text_bar, ";", 0);
184 let mut snippet = SnippetData::new(cm, Some(span_foo_vec1));
185 snippet.push(span_foo_vec0, false, Some(format!("a")));
186 snippet.push(span_foo_vec1, true, Some(format!("b")));
187 snippet.push(span_foo_semi, false, Some(format!("c")));
188 snippet.push(span_bar_vec0, false, Some(format!("d")));
189 snippet.push(span_bar_vec1, false, Some(format!("e")));
190 snippet.push(span_bar_semi, false, Some(format!("f")));
192 let lines = snippet.render_lines();
193 println!("{:#?}", lines);
195 let text: String = make_string(&lines);
197 println!("text=\n{}", text);
199 // Note that the `|>` remain aligned across both files:
200 assert_eq!(&text[..], &r#"
202 3 |> vec.push(vec.pop().unwrap());
213 21 |> vec.pop().unwrap());
222 let name = find_id(&data, 22).unwrap();
224 // Add one more item we forgot to the vector. Silly us.
225 data.push(Data { name: format!("Hera"), id: 66 });
227 // Print everything out.
228 println!("Name: {:?}", name);
229 println!("Data: {:?}", data);
233 let cm = Rc::new(CodeMap::new());
234 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
235 let span_data0 = cm.span_substr(&foo, file_text, "data", 0);
236 let span_data1 = cm.span_substr(&foo, file_text, "data", 1);
237 let span_rbrace = cm.span_substr(&foo, file_text, "}", 3);
239 let mut snippet = SnippetData::new(cm, None);
240 snippet.push(span_data0, false, Some(format!("immutable borrow begins here")));
241 snippet.push(span_data1, false, Some(format!("mutable borrow occurs here")));
242 snippet.push(span_rbrace, false, Some(format!("immutable borrow ends here")));
244 let lines = snippet.render_lines();
245 println!("{:#?}", lines);
247 let text: String = make_string(&lines);
249 println!("text=\n{}", text);
250 assert_eq!(&text[..], &r#"
252 3 |> let name = find_id(&data, 22).unwrap();
253 |> ---- immutable borrow begins here
255 6 |> data.push(Data { name: format!("Hera"), id: 66 });
256 |> ---- mutable borrow occurs here
259 |> - immutable borrow ends here
267 vec.push(vec.pop().unwrap());
271 let cm = Rc::new(CodeMap::new());
272 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
273 let span0 = cm.span_substr(&foo, file_text, "vec.push", 0);
274 let span1 = cm.span_substr(&foo, file_text, "vec", 0);
275 let span2 = cm.span_substr(&foo, file_text, "ec.push", 0);
276 let span3 = cm.span_substr(&foo, file_text, "unwrap", 0);
278 let mut snippet = SnippetData::new(cm, None);
279 snippet.push(span0, false, Some(format!("A")));
280 snippet.push(span1, false, Some(format!("B")));
281 snippet.push(span2, false, Some(format!("C")));
282 snippet.push(span3, false, Some(format!("D")));
284 let lines = snippet.render_lines();
285 println!("{:#?}", lines);
286 let text: String = make_string(&lines);
288 println!("text=r#\"\n{}\".trim_left()", text);
289 assert_eq!(&text[..], &r#"
291 3 |> vec.push(vec.pop().unwrap());
301 fn one_line_out_of_order() {
304 vec.push(vec.pop().unwrap());
308 let cm = Rc::new(CodeMap::new());
309 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
310 let span_vec0 = cm.span_substr(&foo, file_text, "vec", 0);
311 let span_vec1 = cm.span_substr(&foo, file_text, "vec", 1);
312 let span_semi = cm.span_substr(&foo, file_text, ";", 0);
314 // intentionally don't push the snippets left to right
315 let mut snippet = SnippetData::new(cm, None);
316 snippet.push(span_vec1, false, Some(format!("error occurs here")));
317 snippet.push(span_vec0, false, Some(format!("previous borrow of `vec` occurs here")));
318 snippet.push(span_semi, false, Some(format!("previous borrow ends here")));
320 let lines = snippet.render_lines();
321 println!("{:#?}", lines);
322 let text: String = make_string(&lines);
324 println!("text=r#\"\n{}\".trim_left()", text);
325 assert_eq!(&text[..], &r#"
327 3 |> vec.push(vec.pop().unwrap());
328 |> --- --- - previous borrow ends here
330 |> | error occurs here
331 |> previous borrow of `vec` occurs here
336 fn elide_unnecessary_lines() {
339 let mut vec = vec![0, 1, 2];
349 let cm = Rc::new(CodeMap::new());
350 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
351 let span_vec0 = cm.span_substr(&foo, file_text, "vec", 3);
352 let span_vec1 = cm.span_substr(&foo, file_text, "vec", 8);
354 let mut snippet = SnippetData::new(cm, None);
355 snippet.push(span_vec0, false, Some(format!("`vec` moved here because it \
356 has type `collections::vec::Vec<i32>`")));
357 snippet.push(span_vec1, false, Some(format!("use of moved value: `vec`")));
359 let lines = snippet.render_lines();
360 println!("{:#?}", lines);
361 let text: String = make_string(&lines);
362 println!("text=r#\"\n{}\".trim_left()", text);
363 assert_eq!(&text[..], &r#"
365 4 |> let mut vec2 = vec;
366 |> --- `vec` moved here because it has type `collections::vec::Vec<i32>`
369 |> --- use of moved value: `vec`
374 fn spans_without_labels() {
377 let mut vec = vec![0, 1, 2];
387 let cm = Rc::new(CodeMap::new());
388 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
390 let mut snippet = SnippetData::new(cm.clone(), None);
392 let span_veci = cm.span_substr(&foo, file_text, "vec", i);
393 snippet.push(span_veci, false, None);
396 let lines = snippet.render_lines();
397 let text: String = make_string(&lines);
398 println!("text=&r#\"\n{}\n\"#[1..]", text);
399 assert_eq!(text, &r#"
401 3 |> let mut vec = vec![0, 1, 2];
403 4 |> let mut vec2 = vec;
409 fn span_long_selection() {
411 impl SomeTrait for () {
420 let cm = Rc::new(CodeMap::new());
421 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
423 let mut snippet = SnippetData::new(cm.clone(), None);
424 let fn_span = cm.span_substr(&foo, file_text, "fn", 0);
425 let rbrace_span = cm.span_substr(&foo, file_text, "}", 0);
426 snippet.push(splice(fn_span, rbrace_span), false, None);
427 let lines = snippet.render_lines();
428 let text: String = make_string(&lines);
429 println!("r#\"\n{}\"", text);
430 assert_eq!(text, &r#"
432 3 |> fn foo(x: u32) {
438 fn span_overlap_label() {
439 // Test that we don't put `x_span` to the right of its highlight,
440 // since there is another highlight that overlaps it.
448 let cm = Rc::new(CodeMap::new());
449 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
451 let mut snippet = SnippetData::new(cm.clone(), None);
452 let fn_span = cm.span_substr(&foo, file_text, "fn foo(x: u32)", 0);
453 let x_span = cm.span_substr(&foo, file_text, "x", 0);
454 snippet.push(fn_span, false, Some(format!("fn_span")));
455 snippet.push(x_span, false, Some(format!("x_span")));
456 let lines = snippet.render_lines();
457 let text: String = make_string(&lines);
458 println!("r#\"\n{}\"", text);
459 assert_eq!(text, &r#"
461 2 |> fn foo(x: u32) {
470 fn span_overlap_label2() {
471 // Test that we don't put `x_span` to the right of its highlight,
472 // since there is another highlight that overlaps it. In this
473 // case, the overlap is only at the beginning, but it's still
474 // better to show the beginning more clearly.
482 let cm = Rc::new(CodeMap::new());
483 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
485 let mut snippet = SnippetData::new(cm.clone(), None);
486 let fn_span = cm.span_substr(&foo, file_text, "fn foo(x", 0);
487 let x_span = cm.span_substr(&foo, file_text, "x: u32)", 0);
488 snippet.push(fn_span, false, Some(format!("fn_span")));
489 snippet.push(x_span, false, Some(format!("x_span")));
490 let lines = snippet.render_lines();
491 let text: String = make_string(&lines);
492 println!("r#\"\n{}\"", text);
493 assert_eq!(text, &r#"
495 2 |> fn foo(x: u32) {
504 fn span_overlap_label3() {
505 // Test that we don't put `x_span` to the right of its highlight,
506 // since there is another highlight that overlaps it. In this
507 // case, the overlap is only at the beginning, but it's still
508 // better to show the beginning more clearly.
519 let cm = Rc::new(CodeMap::new());
520 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
522 let mut snippet = SnippetData::new(cm.clone(), None);
525 let closure_start_span = cm.span_substr(&foo, file_text, "||", 0);
526 let closure_end_span = cm.span_substr(&foo, file_text, "}", 0);
527 splice(closure_start_span, closure_end_span)
530 let inner_span = cm.span_substr(&foo, file_text, "inner", 0);
532 snippet.push(closure_span, false, Some(format!("foo")));
533 snippet.push(inner_span, false, Some(format!("bar")));
535 let lines = snippet.render_lines();
536 let text: String = make_string(&lines);
537 println!("r#\"\n{}\"", text);
538 assert_eq!(text, &r#"
540 3 |> let closure = || {
549 // In one of the unit tests, we found that the parser sometimes
550 // gives empty spans, and in particular it supplied an EOF span
551 // like this one, which points at the very end. We want to
552 // fallback gracefully in this case.
558 impl !Sync for Foo {}
560 unsafe impl Send for &'static Foo {
561 // error: cross-crate traits with a default impl, like `core::marker::Send`,
562 // can only be implemented for a struct/enum type, not
567 let cm = Rc::new(CodeMap::new());
568 let foo = cm.new_filemap_and_lines("foo.rs", file_text);
570 let mut rbrace_span = cm.span_substr(&foo, file_text, "}", 1);
571 rbrace_span.lo = rbrace_span.hi;
573 let mut snippet = SnippetData::new(cm.clone(), Some(rbrace_span));
574 snippet.push(rbrace_span, false, None);
575 let lines = snippet.render_lines();
576 let text: String = make_string(&lines);
577 println!("r#\"\n{}\"", text);
578 assert_eq!(text, &r#"