diff --git a/src/renderer/source_map.rs b/src/renderer/source_map.rs index d42dccc..eca057e 100644 --- a/src/renderer/source_map.rs +++ b/src/renderer/source_map.rs @@ -194,8 +194,7 @@ impl<'a> SourceMap<'a> { let mut primary_spans = vec![]; // Find overlapping multiline annotations, put them at different depths - multiline_annotations - .sort_by_key(|ml| (ml.start.line, usize::MAX - ml.end.line, ml.start.byte)); + multiline_annotations.sort_by_key(|ml| (ml.start.line, usize::MAX - ml.end.line)); for ann in multiline_annotations.clone() { if ann.kind.is_primary() { primary_spans.push((ann.start, ann.end)); diff --git a/tests/formatter.rs b/tests/formatter.rs index 7e25a01..bf99853 100644 --- a/tests/formatter.rs +++ b/tests/formatter.rs @@ -887,15 +887,15 @@ bar = { version = "0.1.0", optional = true } error: unused optional dependency | 4 | bar = { version = "0.1.0", optional = true } - | _________^__________________--------------^ - | | | | - | |_________| This should also be long but not too long + | __________^__________________--------------^ + | | | | + | | _________| This should also be long but not too long | || 5 | || this is another line 6 | || so is this 7 | || bar = { version = "0.1.0", optional = true } | ||_________________________^________________^ I need this to be really long so I can test overlaps - | |__________________________| + | |_________________________| | I need this to be really long so I can test overlaps "#]]; let renderer = Renderer::plain(); @@ -940,16 +940,16 @@ this is another line error: unused optional dependency | 4 | bar = { version = "0.1.0", optional = true } - | __________^__________________--------------^ - | | | | - | |__________| This should also be long but not too long + | ___________^__________________--------------^ + | | | | + | | __________| This should also be long but not too long | || 5 | || this is another line | || ____^ 6 | ||| so is this 7 | ||| bar = { version = "0.1.0", optional = true } | |||_________________________^________________^ I need this to be really long so I can test overlaps - | |_|_________________________| + | ||_________________________| | | I need this to be really long so I can test overlaps 8 | | this is another line | |____^ I need this to be really long so I can test overlaps diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index 642c84e..cf33969 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2,7 +2,7 @@ //! //! [parser-tests]: https://github.com/rust-lang/rust/blob/894f7a4ba6554d3797404bbf550d9919df060b97/compiler/rustc_parse/src/parser/tests.rs -use annotate_snippets::{AnnotationKind, Group, Level, Origin, Renderer, Snippet}; +use annotate_snippets::{AnnotationKind, Group, Level, Origin, Patch, Renderer, Snippet}; use annotate_snippets::renderer::OutputTheme; use snapbox::{assert_data_eq, str}; @@ -2020,3 +2020,94 @@ LL | ... = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...0, 0, 0, 0, 0, 0, 0, 0, 0 .term_width(120); assert_data_eq!(renderer.render(input), expected); } + +#[test] +fn lint_map_unit_fn() { + // tests/ui/lint/lint_map_unit_fn.rs + let source = r#"#![deny(map_unit_fn)] + +fn foo(items: &mut Vec) { + items.sort(); +} + +fn main() { + let mut x: Vec> = vec![vec![0, 2, 1], vec![5, 4, 3]]; + x.iter_mut().map(foo); + //~^ ERROR `Iterator::map` call that discard the iterator's values + x.iter_mut().map(|items| { + //~^ ERROR `Iterator::map` call that discard the iterator's values + items.sort(); + }); + let f = |items: &mut Vec| { + items.sort(); + }; + x.iter_mut().map(f); + //~^ ERROR `Iterator::map` call that discard the iterator's values +} +"#; + + let input = Level::ERROR + .header("`Iterator::map` call that discard the iterator's values") + .group( + Group::new() + .element( + Snippet::source(source) + .origin("$DIR/lint_map_unit_fn.rs") + .fold(true) + .annotation(AnnotationKind::Context.span(271..278).label( + "this function returns `()`, which is likely not what you wanted", + )) + .annotation( + AnnotationKind::Context + .span(271..379) + .label("called `Iterator::map` with callable that returns `()`"), + ) + .annotation( + AnnotationKind::Context + .span(267..380) + .label("after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items") + ) + .annotation(AnnotationKind::Primary.span(267..380)), + ) + .element( + Level::NOTE.title("`Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated")), + ) + .group( + Group::new() + .element(Level::HELP.title("you might have meant to use `Iterator::for_each`")) + .element( + Snippet::source(source) + .origin("$DIR/lint_map_unit_fn.rs") + .fold(true) + .patch(Patch::new(267..270, r#"for_each"#)), + ), + ); + + let expected = str![[r#" +error: `Iterator::map` call that discard the iterator's values + --> $DIR/lint_map_unit_fn.rs:11:18 + | +LL | x.iter_mut().map(|items| { + | ^ ------- + | | | + | ____________________|___this function returns `()`, which is likely not what you wanted + | | __________________| + | | | +LL | | | //~^ ERROR `Iterator::map` call that discard the iterator's values +LL | | | items.sort(); +LL | | | }); + | | | -^ after this call to map, the resulting iterator is `impl Iterator`, which means the only information carried by the iterator is the number of items + | | |_____|| + | |_______| + | called `Iterator::map` with callable that returns `()` + | + = note: `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated +help: you might have meant to use `Iterator::for_each` + | +LL - x.iter_mut().map(|items| { +LL + x.iter_mut().for_each(|items| { + | +"#]]; + let renderer = Renderer::plain().anonymized_line_numbers(true); + assert_data_eq!(renderer.render(input), expected); +}