diff --git a/src/renderer/render.rs b/src/renderer/render.rs index e8cb5fa..1f5bfc5 100644 --- a/src/renderer/render.rs +++ b/src/renderer/render.rs @@ -1774,7 +1774,10 @@ fn emit_suggestion_default( // too bad to begin with, so we side-step that issue here. for (i, line) in snippet.lines().enumerate() { let line = normalize_whitespace(line); - let row = row_num - 2 - (newlines - i - 1); + // Going lower than buffer_offset (+ 1) would mean + // overwriting existing content in the buffer + let min_row = buffer_offset + usize::from(!matches_previous_suggestion); + let row = (row_num - 2 - (newlines - i - 1)).max(min_row); // On the first line, we highlight between the start of the part // span, and the end of that line. // On the last line, we highlight between the start of the line, and diff --git a/tests/color/highlight_duplicated_diff_lines.ascii.term.svg b/tests/color/highlight_duplicated_diff_lines.ascii.term.svg new file mode 100644 index 0000000..cd3db7b --- /dev/null +++ b/tests/color/highlight_duplicated_diff_lines.ascii.term.svg @@ -0,0 +1,62 @@ + + + + + + + error[E0061]: this function takes 6 arguments but 7 arguments were supplied + + --> $DIR/wrong-highlight-span-extra-arguments-147070.rs:17:15 + + | + + 17 | let foo = Thingie::new( + + | ^^^^^^^^^^^^ + + ... + + 24 | String::from(""), + + | ---------------- unexpected argument #7 of type `String` + + | + + note: associated function defined here + + --> $DIR/wrong-highlight-span-extra-arguments-147070.rs:4:19 + + | + + 4 | pub(crate) fn new( + + | ^^^ + + help: remove the extra argument + + | + + 23 - String::from(""), + + | + + + + diff --git a/tests/color/highlight_duplicated_diff_lines.rs b/tests/color/highlight_duplicated_diff_lines.rs new file mode 100644 index 0000000..4f26e8c --- /dev/null +++ b/tests/color/highlight_duplicated_diff_lines.rs @@ -0,0 +1,75 @@ +use annotate_snippets::{renderer::DecorStyle, AnnotationKind, Level, Patch, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + // https://github.com/rust-lang/rust/blob/4b94758d2ba7d0ef71ccf5fde29ce4bc5d6fe2a4/tests/ui/argument-suggestions/wrong-highlight-span-extra-arguments-147070.rs + + let source = r#"struct Thingie; + +impl Thingie { + pub(crate) fn new( + _a: String, + _b: String, + _c: String, + _d: String, + _e: String, + _f: String, + ) -> Self { + unimplemented!() + } +} + +fn main() { + let foo = Thingie::new( + String::from(""), + String::from(""), + String::from(""), + String::from(""), + String::from(""), + String::from(""), + String::from(""), + ); +}"#; + + let path = "$DIR/wrong-highlight-span-extra-arguments-147070.rs"; + + let report = &[ + Level::ERROR + .primary_title("this function takes 6 arguments but 7 arguments were supplied") + .id("E0061") + .element( + Snippet::source(source) + .path(path) + .annotation( + AnnotationKind::Context + .span(429..445) + .label("unexpected argument #7 of type `String`"), + ) + .annotation(AnnotationKind::Primary.span(251..263)), + ), + Level::NOTE + .secondary_title("associated function defined here") + .element( + Snippet::source(source) + .path(path) + .annotation(AnnotationKind::Primary.span(50..53)), + ), + Level::HELP + .secondary_title("remove the extra argument") + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(419..445, "")), + ), + ]; + + let expected_ascii = file!["highlight_duplicated_diff_lines.ascii.term.svg": TermSvg]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(report), expected_ascii); + + let expected_unicode = file!["highlight_duplicated_diff_lines.unicode.term.svg": TermSvg]; + let renderer = renderer.decor_style(DecorStyle::Unicode); + assert_data_eq!(renderer.render(report), expected_unicode); +} diff --git a/tests/color/highlight_duplicated_diff_lines.unicode.term.svg b/tests/color/highlight_duplicated_diff_lines.unicode.term.svg new file mode 100644 index 0000000..5ae70d1 --- /dev/null +++ b/tests/color/highlight_duplicated_diff_lines.unicode.term.svg @@ -0,0 +1,62 @@ + + + + + + + error[E0061]: this function takes 6 arguments but 7 arguments were supplied + + ╭▸ $DIR/wrong-highlight-span-extra-arguments-147070.rs:17:15 + + + + 17 let foo = Thingie::new( + + ━━━━━━━━━━━━ + + + + 24 String::from(""), + + ──────────────── unexpected argument #7 of type `String` + + ╰╴ + + note: associated function defined here + + ╭▸ $DIR/wrong-highlight-span-extra-arguments-147070.rs:4:19 + + + + 4 pub(crate) fn new( + + ╰╴ ━━━ + + help: remove the extra argument + + ╭╴ + + 23 - String::from(""), + + ╰╴ + + + + diff --git a/tests/color/main.rs b/tests/color/main.rs index f61e113..7d78f4b 100644 --- a/tests/color/main.rs +++ b/tests/color/main.rs @@ -9,10 +9,13 @@ mod fold_ann_multiline; mod fold_bad_origin_line; mod fold_leading; mod fold_trailing; +mod highlight_duplicated_diff_lines; mod highlight_source; mod issue_9; mod multiline_removal_suggestion; mod multiple_annotations; +mod multiple_highlight_duplicated; +mod multiple_multiline_removal; mod primary_title_second_group; mod simple; mod strip_line; diff --git a/tests/color/multiple_highlight_duplicated.ascii.term.svg b/tests/color/multiple_highlight_duplicated.ascii.term.svg new file mode 100644 index 0000000..a38c0fa --- /dev/null +++ b/tests/color/multiple_highlight_duplicated.ascii.term.svg @@ -0,0 +1,78 @@ + + + + + + + error[E0061]: this function takes 6 arguments but 7 arguments were supplied + + --> $DIR/wrong-highlight-span-extra-arguments-147070.rs:17:15 + + | + + 17 | let foo = Thingie::new( + + | ^^^^^^^^^^^^ + + ... + + 24 | String::from(""), + + | ---------------- unexpected argument #7 of type `String` + + | + + note: associated function defined here + + --> $DIR/wrong-highlight-span-extra-arguments-147070.rs:4:19 + + | + + 4 | pub(crate) fn new( + + | ^^^ + + help: remove the extra argument + + | + + 23 - String::from(""), + + | + + 18 - String::from(""), + + | + + 18 - String::from(""), + + | + + 23 - String::from(""), + + | + + 23 - String::from(""), + + | + + + + diff --git a/tests/color/multiple_highlight_duplicated.rs b/tests/color/multiple_highlight_duplicated.rs new file mode 100644 index 0000000..625584d --- /dev/null +++ b/tests/color/multiple_highlight_duplicated.rs @@ -0,0 +1,93 @@ +use annotate_snippets::{renderer::DecorStyle, AnnotationKind, Level, Patch, Renderer, Snippet}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + let source = r#"struct Thingie; + +impl Thingie { + pub(crate) fn new( + _a: String, + _b: String, + _c: String, + _d: String, + _e: String, + _f: String, + ) -> Self { + unimplemented!() + } +} + +fn main() { + let foo = Thingie::new( + String::from(""), + String::from(""), + String::from(""), + String::from(""), + String::from(""), + String::from(""), + String::from(""), + ); +}"#; + + let path = "$DIR/wrong-highlight-span-extra-arguments-147070.rs"; + + let report = &[ + Level::ERROR + .primary_title("this function takes 6 arguments but 7 arguments were supplied") + .id("E0061") + .element( + Snippet::source(source) + .path(path) + .annotation( + AnnotationKind::Context + .span(429..445) + .label("unexpected argument #7 of type `String`"), + ) + .annotation(AnnotationKind::Primary.span(251..263)), + ), + Level::NOTE + .secondary_title("associated function defined here") + .element( + Snippet::source(source) + .path(path) + .annotation(AnnotationKind::Primary.span(50..53)), + ), + Level::HELP + .secondary_title("remove the extra argument") + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(419..445, "")), + ) + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(266..292, "")), + ) + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(289..315, "")), + ) + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(403..420, "")), + ) + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(419..445, "")), + ), + ]; + + let expected_ascii = file!["multiple_highlight_duplicated.ascii.term.svg": TermSvg]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(report), expected_ascii); + + let expected_unicode = file!["multiple_highlight_duplicated.unicode.term.svg": TermSvg]; + let renderer = renderer.decor_style(DecorStyle::Unicode); + assert_data_eq!(renderer.render(report), expected_unicode); +} diff --git a/tests/color/multiple_highlight_duplicated.unicode.term.svg b/tests/color/multiple_highlight_duplicated.unicode.term.svg new file mode 100644 index 0000000..8bcafa2 --- /dev/null +++ b/tests/color/multiple_highlight_duplicated.unicode.term.svg @@ -0,0 +1,78 @@ + + + + + + + error[E0061]: this function takes 6 arguments but 7 arguments were supplied + + ╭▸ $DIR/wrong-highlight-span-extra-arguments-147070.rs:17:15 + + + + 17 let foo = Thingie::new( + + ━━━━━━━━━━━━ + + + + 24 String::from(""), + + ──────────────── unexpected argument #7 of type `String` + + ╰╴ + + note: associated function defined here + + ╭▸ $DIR/wrong-highlight-span-extra-arguments-147070.rs:4:19 + + + + 4 pub(crate) fn new( + + ╰╴ ━━━ + + help: remove the extra argument + + ╭╴ + + 23 - String::from(""), + + ├╴ + + 18 - String::from(""), + + ├╴ + + 18 - String::from(""), + + ├╴ + + 23 - String::from(""), + + ├╴ + + 23 - String::from(""), + + ╰╴ + + + + diff --git a/tests/color/multiple_multiline_removal.ascii.term.svg b/tests/color/multiple_multiline_removal.ascii.term.svg new file mode 100644 index 0000000..ac3afa1 --- /dev/null +++ b/tests/color/multiple_multiline_removal.ascii.term.svg @@ -0,0 +1,114 @@ + + + + + + + error[E0423]: cannot initialize a tuple struct which contains private fields + + --> $DIR/suggest-box-new.rs:8:19 + + | + + 8 | wtf: Some(Box(U { + + | ^^^ + + | + + note: constructor is not visible here due to private fields + + --> $SRC_DIR/alloc/src/boxed.rs:234:2 + + | + + = note: private field + + | + + = note: private field + + help: you might have meant to use an associated function to build this type + + | + + 8 - wtf: Some(Box(U { + + 9 - wtf: None, + + 10 - x: (), + + 11 - })), + + 8 + wtf: Some(Box::new(_)), + + | + + 8 - wtf: Some(Box(U { + + 9 - wtf: None, + + 10 - x: (), + + 11 - })), + + 8 + wtf: Some(Box::new_uninit()), + + | + + 8 - wtf: Some(Box(U { + + 9 - wtf: None, + + 10 - x: (), + + 11 - })), + + 8 + wtf: Some(Box::new_zeroed()), + + | + + 8 - wtf: Some(Box(U { + + 9 - wtf: None, + + 10 - x: (), + + 11 - })), + + 8 + wtf: Some(Box::new_in(_, _)), + + | + + = and 12 other candidates + + help: consider using the `Default` trait + + | + + 8 - wtf: Some(Box(U { + + 8 + wtf: Some(<Box as std::default::Default>::default()), + + | + + + + diff --git a/tests/color/multiple_multiline_removal.rs b/tests/color/multiple_multiline_removal.rs new file mode 100644 index 0000000..ea38a36 --- /dev/null +++ b/tests/color/multiple_multiline_removal.rs @@ -0,0 +1,93 @@ +use annotate_snippets::{ + renderer::DecorStyle, AnnotationKind, Level, Origin, Padding, Patch, Renderer, Snippet, +}; + +use snapbox::{assert_data_eq, file}; + +#[test] +fn case() { + // https://github.com/rust-lang/rust/blob/4b94758d2ba7d0ef71ccf5fde29ce4bc5d6fe2a4/tests/ui/suggestions/multi-suggestion.rs + + let source = r#"#![allow(dead_code)] +struct U { + wtf: Option>>, + x: T, +} +fn main() { + U { + wtf: Some(Box(U { + wtf: None, + x: (), + })), + x: () + }; + let _ = std::collections::HashMap(); + let _ = std::collections::HashMap {}; + let _ = Box {}; +} +"#; + let path = "$DIR/suggest-box-new.rs"; + let secondary_path = "$SRC_DIR/alloc/src/boxed.rs"; + + let report = &[ + Level::ERROR + .primary_title("cannot initialize a tuple struct which contains private fields") + .id("E0423") + .element( + Snippet::source(source) + .path(path) + .annotation(AnnotationKind::Primary.span(114..117)), + ), + Level::NOTE + .secondary_title("constructor is not visible here due to private fields") + .element(Origin::path(secondary_path).line(234).char_column(2)) + .element(Padding) + .element(Level::NOTE.message("private field")) + .element(Padding) + .element(Level::NOTE.message("private field")), + Level::HELP + .secondary_title( + "you might have meant to use an associated function to build this type", + ) + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(117..174, "::new(_)")), + ) + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(117..174, "::new_uninit()")), + ) + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(117..174, "::new_zeroed()")), + ) + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(117..174, "::new_in(_, _)")), + ) + .element(Level::NOTE.no_name().message("and 12 other candidates")), + Level::HELP + .secondary_title("consider using the `Default` trait") + .element( + Snippet::source(source) + .path(path) + .patch(Patch::new(114..114, "<")) + .patch(Patch::new( + 117..174, + " as std::default::Default>::default()", + )), + ), + ]; + + let expected_ascii = file!["multiple_multiline_removal.ascii.term.svg": TermSvg]; + let renderer = Renderer::styled(); + assert_data_eq!(renderer.render(report), expected_ascii); + + let expected_unicode = file!["multiple_multiline_removal.unicode.term.svg": TermSvg]; + let renderer = renderer.decor_style(DecorStyle::Unicode); + assert_data_eq!(renderer.render(report), expected_unicode); +} diff --git a/tests/color/multiple_multiline_removal.unicode.term.svg b/tests/color/multiple_multiline_removal.unicode.term.svg new file mode 100644 index 0000000..ce8306d --- /dev/null +++ b/tests/color/multiple_multiline_removal.unicode.term.svg @@ -0,0 +1,114 @@ + + + + + + + error[E0423]: cannot initialize a tuple struct which contains private fields + + ╭▸ $DIR/suggest-box-new.rs:8:19 + + + + 8 wtf: Some(Box(U { + + ━━━ + + ╰╴ + + note: constructor is not visible here due to private fields + + ╭▸ $SRC_DIR/alloc/src/boxed.rs:234:2 + + + + note: private field + + + + note: private field + + help: you might have meant to use an associated function to build this type + + ╭╴ + + 8 - wtf: Some(Box(U { + + 9 - wtf: None, + + 10 - x: (), + + 11 - })), + + 8 + wtf: Some(Box::new(_)), + + ├╴ + + 8 - wtf: Some(Box(U { + + 9 - wtf: None, + + 10 - x: (), + + 11 - })), + + 8 + wtf: Some(Box::new_uninit()), + + ├╴ + + 8 - wtf: Some(Box(U { + + 9 - wtf: None, + + 10 - x: (), + + 11 - })), + + 8 + wtf: Some(Box::new_zeroed()), + + ├╴ + + 8 - wtf: Some(Box(U { + + 9 - wtf: None, + + 10 - x: (), + + 11 - })), + + 8 + wtf: Some(Box::new_in(_, _)), + + + + and 12 other candidates + + help: consider using the `Default` trait + + ╭╴ + + 8 - wtf: Some(Box(U { + + 8 + wtf: Some(<Box as std::default::Default>::default()), + + ╰╴ + + + + diff --git a/typos.toml b/typos.toml new file mode 100644 index 0000000..708a9e1 --- /dev/null +++ b/typos.toml @@ -0,0 +1,2 @@ +[default.extend-words] +Thingie = "Thingie"