Skip to content

Commit 20b2070

Browse files
authored
Merge pull request #254 from Muscraft/annotation-overlap
fix: Match rustc's annotation overlap
2 parents 9ba3def + 9e25598 commit 20b2070

File tree

2 files changed

+250
-3
lines changed

2 files changed

+250
-3
lines changed

src/renderer/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,7 @@ impl Renderer {
11671167
// otherwise the lines would end up needing to go over a message.
11681168

11691169
let mut annotations = line_info.annotations.clone();
1170-
annotations.sort_by_key(|a| Reverse(a.start.display));
1170+
annotations.sort_by_key(|a| Reverse((a.start.display, a.start.char)));
11711171

11721172
// First, figure out where each label will be positioned.
11731173
//
@@ -1250,7 +1250,9 @@ impl Renderer {
12501250
// If we're overlapping with an un-labelled annotation with the same span
12511251
// we can just merge them in the output
12521252
if next.start.display == annotation.start.display
1253+
&& next.start.char == annotation.start.char
12531254
&& next.end.display == annotation.end.display
1255+
&& next.end.char == annotation.end.char
12541256
&& !next.has_label()
12551257
{
12561258
continue;
@@ -1284,7 +1286,7 @@ impl Renderer {
12841286
&& next.takes_space())
12851287
|| (annotation.takes_space() && next.takes_space())
12861288
|| (overlaps(next, annotation, l)
1287-
&& next.end.display <= annotation.end.display
1289+
&& (next.end.display, next.end.char) <= (annotation.end.display, annotation.end.char)
12881290
&& next.has_label()
12891291
&& p == 0)
12901292
// Avoid #42595.

tests/rustc_tests.rs

Lines changed: 246 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use annotate_snippets::{AnnotationKind, Group, Level, Origin, Padding, Patch, Renderer, Snippet};
66

77
use annotate_snippets::renderer::OutputTheme;
8-
use snapbox::{assert_data_eq, str};
8+
use snapbox::{assert_data_eq, str, IntoData};
99

1010
#[test]
1111
fn ends_on_col0() {
@@ -3445,3 +3445,248 @@ LL | let _: S::<bool>::Pr = ();
34453445
let renderer = Renderer::plain().anonymized_line_numbers(true);
34463446
assert_data_eq!(renderer.render(input), expected);
34473447
}
3448+
3449+
#[test]
3450+
fn unsafe_extern_suggestion() {
3451+
// tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs
3452+
3453+
let source = r#"//@ run-rustfix
3454+
3455+
#![deny(missing_unsafe_on_extern)]
3456+
#![allow(unused)]
3457+
3458+
extern "C" {
3459+
//~^ ERROR extern blocks should be unsafe [missing_unsafe_on_extern]
3460+
//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
3461+
static TEST1: i32;
3462+
fn test1(i: i32);
3463+
}
3464+
3465+
unsafe extern "C" {
3466+
static TEST2: i32;
3467+
fn test2(i: i32);
3468+
}
3469+
3470+
fn main() {}
3471+
"#;
3472+
3473+
let title_0 =
3474+
"this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!";
3475+
let title_1 = "for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-extern.html>";
3476+
3477+
let input = &[
3478+
Group::with_title(Level::ERROR.title("extern blocks should be unsafe"))
3479+
.element(
3480+
Snippet::source(source)
3481+
.path("$DIR/unsafe-extern-suggestion.rs")
3482+
.annotation(
3483+
AnnotationKind::Context
3484+
.span(71..71)
3485+
.label("help: needs `unsafe` before the extern keyword: `unsafe`"),
3486+
)
3487+
.annotation(AnnotationKind::Primary.span(71..303)),
3488+
)
3489+
.element(Level::WARNING.message(title_0))
3490+
.element(Level::NOTE.message(title_1)),
3491+
Group::with_title(Level::NOTE.title("the lint level is defined here")).element(
3492+
Snippet::source(source)
3493+
.path("$DIR/unsafe-extern-suggestion.rs")
3494+
.annotation(AnnotationKind::Primary.span(25..49)),
3495+
),
3496+
];
3497+
3498+
let expected = str![[r#"
3499+
error: extern blocks should be unsafe
3500+
--> $DIR/unsafe-extern-suggestion.rs:6:1
3501+
|
3502+
LL | extern "C" {
3503+
| ^
3504+
| |
3505+
| _help: needs `unsafe` before the extern keyword: `unsafe`
3506+
| |
3507+
LL | | //~^ ERROR extern blocks should be unsafe [missing_unsafe_on_extern]
3508+
LL | | //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
3509+
LL | | static TEST1: i32;
3510+
LL | | fn test1(i: i32);
3511+
LL | | }
3512+
| |_^
3513+
|
3514+
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
3515+
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-extern.html>
3516+
note: the lint level is defined here
3517+
--> $DIR/unsafe-extern-suggestion.rs:3:9
3518+
|
3519+
LL | #![deny(missing_unsafe_on_extern)]
3520+
| ^^^^^^^^^^^^^^^^^^^^^^^^
3521+
"#]];
3522+
let renderer = Renderer::plain().anonymized_line_numbers(true);
3523+
assert_data_eq!(renderer.render(input), expected);
3524+
}
3525+
3526+
#[test]
3527+
fn alloc_error_handler_bad_signature_2() {
3528+
// tests/ui/alloc-error/alloc-error-handler-bad-signature-2.rs
3529+
3530+
let source = r#"//@ compile-flags:-C panic=abort
3531+
3532+
#![feature(alloc_error_handler)]
3533+
#![no_std]
3534+
#![no_main]
3535+
3536+
struct Layout;
3537+
3538+
#[alloc_error_handler]
3539+
fn oom(
3540+
info: Layout, //~^ ERROR mismatched types
3541+
) { //~^^ ERROR mismatched types
3542+
loop {}
3543+
}
3544+
3545+
#[panic_handler]
3546+
fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
3547+
"#;
3548+
let title_0 =
3549+
"`core::alloc::Layout` and `Layout` have similar names, but are actually distinct types";
3550+
3551+
let input = &[
3552+
Group::with_title(Level::ERROR.title("mismatched types").id("E0308"))
3553+
.element(
3554+
Snippet::source(source)
3555+
.path("$DIR/alloc-error-handler-bad-signature-2.rs")
3556+
.annotation(
3557+
AnnotationKind::Primary
3558+
.span(130..230)
3559+
.label("expected `Layout`, found `core::alloc::Layout`"),
3560+
)
3561+
.annotation(
3562+
AnnotationKind::Context
3563+
.span(130..185)
3564+
.label("arguments to this function are incorrect"),
3565+
)
3566+
.annotation(
3567+
AnnotationKind::Context
3568+
.span(107..129)
3569+
.label("in this procedural macro expansion"),
3570+
),
3571+
)
3572+
.element(Level::NOTE.message(title_0)),
3573+
Group::with_title(Level::NOTE.title("`core::alloc::Layout` is defined in crate `core`"))
3574+
.element(
3575+
Origin::path("$SRC_DIR/core/src/alloc/layout.rs")
3576+
.line(40)
3577+
.char_column(0)
3578+
.primary(true),
3579+
),
3580+
Group::with_title(Level::NOTE.title("`Layout` is defined in the current crate")).element(
3581+
Snippet::source(source)
3582+
.path("$DIR/alloc-error-handler-bad-signature-2.rs")
3583+
.annotation(AnnotationKind::Primary.span(91..104)),
3584+
),
3585+
Group::with_title(Level::NOTE.title("function defined here")).element(
3586+
Snippet::source(source)
3587+
.path("$DIR/alloc-error-handler-bad-signature-2.rs")
3588+
.annotation(AnnotationKind::Context.span(142..154).label(""))
3589+
.annotation(AnnotationKind::Primary.span(133..136)),
3590+
),
3591+
];
3592+
let expected = str![[r#"
3593+
error[E0308]: mismatched types
3594+
--> $DIR/alloc-error-handler-bad-signature-2.rs:10:1
3595+
|
3596+
LL | #[alloc_error_handler]
3597+
| ---------------------- in this procedural macro expansion
3598+
LL | // fn oom(
3599+
LL | || info: Layout, //~^ ERROR mismatched types
3600+
LL | || ) { //~^^ ERROR mismatched types
3601+
| ||_- arguments to this function are incorrect
3602+
LL | | loop {}
3603+
LL | | }
3604+
| |__^ expected `Layout`, found `core::alloc::Layout`
3605+
|
3606+
= note: `core::alloc::Layout` and `Layout` have similar names, but are actually distinct types
3607+
note: `core::alloc::Layout` is defined in crate `core`
3608+
--> $SRC_DIR/core/src/alloc/layout.rs:40:0
3609+
note: `Layout` is defined in the current crate
3610+
--> $DIR/alloc-error-handler-bad-signature-2.rs:7:1
3611+
|
3612+
LL | struct Layout;
3613+
| ^^^^^^^^^^^^^
3614+
note: function defined here
3615+
--> $DIR/alloc-error-handler-bad-signature-2.rs:10:4
3616+
|
3617+
LL | fn oom(
3618+
| ^^^
3619+
LL | info: Layout, //~^ ERROR mismatched types
3620+
| ------------
3621+
"#]];
3622+
let renderer = Renderer::plain().anonymized_line_numbers(true);
3623+
assert_data_eq!(renderer.render(input), expected);
3624+
}
3625+
3626+
#[test]
3627+
fn str_escape() {
3628+
// tests/ui/str/str-escape.rs
3629+
3630+
let source = r#"//@ check-pass
3631+
// ignore-tidy-tab
3632+
//@ edition: 2021
3633+
3634+
fn main() {
3635+
let s = "\
3636+
3637+
";
3638+
//~^^^ WARNING multiple lines skipped by escaped newline
3639+
assert_eq!(s, "");
3640+
3641+
let s = c"foo\
3642+
  bar
3643+
";
3644+
//~^^^ WARNING whitespace symbol '\u{a0}' is not skipped
3645+
assert_eq!(s, c"foo  bar\n ");
3646+
3647+
let s = "a\
3648+
b";
3649+
assert_eq!(s, "ab");
3650+
3651+
let s = "a\
3652+
b";
3653+
assert_eq!(s, "ab");
3654+
3655+
let s = b"a\
3656+
3657+
b";
3658+
//~^^ WARNING whitespace symbol '\u{c}' is not skipped
3659+
// '\x0c' is ASCII whitespace, but it may not need skipped
3660+
// discussion: https://github.com/rust-lang/rust/pull/108403
3661+
assert_eq!(s, b"a\x0cb");
3662+
}
3663+
"#;
3664+
3665+
let input =
3666+
&[
3667+
Group::with_title(Level::WARNING.title(r#"whitespace symbol '\u{a0}' is not skipped"#))
3668+
.element(
3669+
Snippet::source(source)
3670+
.path("$DIR/str-escape.rs")
3671+
.annotation(
3672+
AnnotationKind::Context
3673+
.span(203..205)
3674+
.label(r#"whitespace symbol '\u{a0}' is not skipped"#),
3675+
)
3676+
.annotation(AnnotationKind::Primary.span(199..205)),
3677+
),
3678+
];
3679+
let expected = str![[r#"
3680+
warning: whitespace symbol '\u{a0}' is not skipped
3681+
--> $DIR/str-escape.rs:12:18
3682+
|
3683+
LL | let s = c"foo\
3684+
| __________________^
3685+
LL | |   bar
3686+
| | ^ whitespace symbol '\u{a0}' is not skipped
3687+
| |___|
3688+
|
3689+
"#]];
3690+
let renderer = Renderer::plain().anonymized_line_numbers(true);
3691+
assert_data_eq!(renderer.render(input), expected.raw());
3692+
}

0 commit comments

Comments
 (0)