diff --git a/CHANGELOG.md b/CHANGELOG.md index b1dc8f20..1ef2b6ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [0.25.0] - 2024-07-24 + +### Added + +### Fixed + +* panics when ui_test tried to show diagnostics on multi-byte chars + +### Changed + +### Removed + ## [0.24.0] - 2024-07-11 diff --git a/Cargo.lock b/Cargo.lock index 4651f696..b5420d09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -454,9 +454,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -558,7 +558,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 3ba3b68e..b712a640 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ui_test" -version = "0.24.0" +version = "0.25.0" edition = "2021" license = "MIT OR Apache-2.0" description = "A test framework for testing rustc diagnostics output" @@ -28,7 +28,7 @@ indicatif = "0.17.6" prettydiff = { version = "0.7", default-features = false } annotate-snippets = { version = "0.11.2" } levenshtein = "1.0.5" -spanned = "0.2.1" +spanned = "0.3.0" [dependencies.regex] version = "1.5.5" diff --git a/src/aux_builds.rs b/src/aux_builds.rs index da8bb8d3..a5e35414 100644 --- a/src/aux_builds.rs +++ b/src/aux_builds.rs @@ -29,7 +29,6 @@ impl Flag for AuxBuilder { ) -> Result<(), Errored> { let aux = &self.aux_file; let aux_dir = config.aux_dir; - let line = aux.line(); let aux_file = if aux.starts_with("..") { aux_dir.parent().unwrap().join(&aux.content) } else { @@ -60,9 +59,8 @@ impl Flag for AuxBuilder { }| Errored { command, errors: vec![Error::Aux { - path: aux_file.to_path_buf(), + path: Spanned::new(aux_file.to_path_buf(), aux.span()), errors, - line, }], stderr, stdout, @@ -84,14 +82,13 @@ pub struct AuxBuilder { impl Build for AuxBuilder { fn build(&self, build_manager: &BuildManager<'_>) -> Result, Errored> { let mut config = build_manager.config().clone(); - let file_contents = Spanned::read_from_file(&self.aux_file.content) - .map_err(|err| Errored { + let file_contents = + Spanned::read_from_file(&self.aux_file.content).map_err(|err| Errored { command: format!("reading aux file `{}`", display(&self.aux_file)), errors: vec![], stderr: err.to_string().into_bytes(), stdout: vec![], - })? - .map(|s| s.into_bytes()); + })?; let comments = Comments::parse(file_contents.as_ref(), &config) .map_err(|errors| Errored::new(errors, "parse aux comments"))?; assert_eq!( diff --git a/src/custom_flags/run.rs b/src/custom_flags/run.rs index 98af12f4..20ed264f 100644 --- a/src/custom_flags/run.rs +++ b/src/custom_flags/run.rs @@ -1,11 +1,8 @@ //! Types used for running tests after they pass compilation use bstr::ByteSlice; -use spanned::{Span, Spanned}; -use std::{ - path::PathBuf, - process::{Command, Output}, -}; +use spanned::Spanned; +use std::process::{Command, Output}; use crate::{ build_manager::BuildManager, display, per_test_config::TestConfig, Error, Errored, TestOk, @@ -116,19 +113,25 @@ fn get_panic_span(stderr: &[u8]) -> Spanned { let Ok(filename) = filename.to_str() else { continue; }; - let Ok(line) = line.parse() else { + let Ok(line) = line.parse::() else { + continue; + }; + let Ok(col) = col.parse::() else { + continue; + }; + let Ok(file) = Spanned::read_from_file(filename) else { + continue; + }; + let Some(line) = line.checked_sub(1) else { continue; }; - let Ok(col) = col.parse() else { + let Some(line) = file.lines().nth(line) else { continue; }; - let span = Span { - file: PathBuf::from(filename), - line_start: line, - line_end: line, - col_start: col, - col_end: col, + let Some(col) = col.checked_sub(1) else { + continue; }; + let span = line.span.inc_col_start(col); return Spanned::new(message.into(), span); } } diff --git a/src/custom_flags/rustfix.rs b/src/custom_flags/rustfix.rs index 371c94b8..c5eaf082 100644 --- a/src/custom_flags/rustfix.rs +++ b/src/custom_flags/rustfix.rs @@ -234,7 +234,7 @@ fn compile_fixed( .iter() .flatten() .chain(diagnostics.messages_from_unknown_file_or_line.iter()) - .find_map(|message| message.line_col.clone()) + .find_map(|message| message.span.clone()) .unwrap_or_default(), ), }], diff --git a/src/diagnostics.rs b/src/diagnostics.rs index fbaeefd5..8c053834 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -56,7 +56,9 @@ pub struct Message { /// The main message of the diagnostic (what will be matched for with `//~`) pub message: String, /// Information about where in the file the message was emitted - pub line_col: Option, + pub line: Option, + /// Exact span information of the message + pub span: Option, /// Identifier of the message (E0XXX for rustc errors, or lint names) pub code: Option, } diff --git a/src/error.rs b/src/error.rs index 295f18c7..87992e97 100644 --- a/src/error.rs +++ b/src/error.rs @@ -56,7 +56,7 @@ pub enum Error { /// The main message of the error. msgs: Vec, /// File and line information of the error. - path: Option>, + path: Option<(PathBuf, NonZeroUsize)>, }, /// A comment failed to parse. InvalidComment { @@ -72,7 +72,7 @@ pub enum Error { /// The comment being looked for kind: String, /// The lines where conflicts happened - lines: Vec, + lines: Vec, }, /// A subcommand (e.g. rustfix) of a test failed. Command { @@ -86,11 +86,9 @@ pub enum Error { /// An auxiliary build failed with its own set of errors. Aux { /// Path to the aux file. - path: PathBuf, + path: Spanned, /// The errors that occurred during the build of the aux file. errors: Vec, - /// The line in which the aux file was requested to be built. - line: NonZeroUsize, }, /// An error occured applying [`rustfix`] suggestions Rustfix(anyhow::Error), diff --git a/src/lib.rs b/src/lib.rs index fdba75b5..de692a42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,8 +139,7 @@ pub fn test_command(mut config: Config, path: &Path) -> Result { config.fill_host_and_target()?; let content = Spanned::read_from_file(path) - .wrap_err_with(|| format!("failed to read {}", display(path)))? - .map(|s| s.into_bytes()); + .wrap_err_with(|| format!("failed to read {}", display(path)))?; let comments = Comments::parse(content.as_ref(), &config) .map_err(|errors| color_eyre::eyre::eyre!("{errors:#?}"))?; let config = TestConfig { @@ -234,9 +233,7 @@ pub fn run_tests_generic( |receive, finished_files_sender| -> Result<()> { for (status, build_manager) in receive { let path = status.path(); - let file_contents = Spanned::read_from_file(path) - .unwrap() - .map(|s| s.into_bytes()); + let file_contents = Spanned::read_from_file(path).unwrap(); let mut config = build_manager.config().clone(); per_file_config(&mut config, &file_contents); let result = match std::panic::catch_unwind(|| { diff --git a/src/parser.rs b/src/parser.rs index 1a008849..06309392 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -59,7 +59,7 @@ impl Comments { } if let Some(found) = f(rev).into_inner() { if result.is_some() { - errors.push(found.line()); + errors.push(found.span); } else { result = found.into(); } @@ -911,7 +911,7 @@ impl CommentParser<&mut Revisioned> { self.error(pattern.span(), format!( "//~^ pattern is trying to refer to {} lines above, but there are only {} lines above", offset, - pattern.line().get() - 1, + current_line.get() - 1, )); return ParsePatternResult::ErrorAbove { match_line: current_line, diff --git a/src/parser/tests.rs b/src/parser/tests.rs index c1260fe4..0a994aad 100644 --- a/src/parser/tests.rs +++ b/src/parser/tests.rs @@ -7,6 +7,17 @@ use crate::{ use super::Comments; +macro_rules! line { + ($thing:expr, $s:expr) => {{ + let file = Spanned::dummy($s.as_bytes()); + let pos = file + .lines() + .position(|line| line.span.bytes.contains(&$thing.bytes.start)) + .unwrap(); + pos + }}; +} + #[test] fn parse_simple_comment() { let s = r" @@ -23,7 +34,7 @@ fn main() { let ErrorMatchKind::Pattern { pattern, .. } = &revisioned.error_matches[0].kind else { panic!("expected pattern matcher"); }; - assert_eq!(pattern.line().get(), 5); + assert_ne!(line!(&pattern.span, s), 5); match &**pattern { Pattern::SubString(s) => { assert_eq!( @@ -49,7 +60,7 @@ fn main() { let ErrorMatchKind::Code(code) = &revisioned.error_matches[0].kind else { panic!("expected diagnostic code matcher"); }; - assert_eq!(code.line().get(), 3); + assert_eq!(line!(&code.span, s), 3); assert_eq!(**code, "E0308"); } @@ -66,7 +77,7 @@ fn main() { println!("parsed comments: {:#?}", errors); assert_eq!(errors.len(), 1); match &errors[0] { - Error::InvalidComment { msg, span } if span.line_start.get() == 5 => { + Error::InvalidComment { msg, span } if line!(span, s) == 5 => { assert_eq!(msg, "text found after error code `encountered`") } _ => unreachable!(), @@ -86,7 +97,7 @@ use std::mem; let revisioned = &comments.revisioned[&vec![]]; let pat = &revisioned.error_in_other_files[0]; assert_eq!(format!("{:?}", **pat), r#"SubString("foomp")"#); - assert_eq!(pat.line().get(), 2); + assert_eq!(line!(pat.span, s), 2); } #[test] @@ -102,7 +113,7 @@ use std::mem; let revisioned = &comments.revisioned[&vec![]]; let pat = &revisioned.error_in_other_files[0]; assert_eq!(format!("{:?}", **pat), r#"Regex(Regex("foomp"))"#); - assert_eq!(pat.line().get(), 2); + assert_eq!(line!(pat.span, s), 2); } #[test] @@ -116,13 +127,13 @@ use std::mem; println!("parsed comments: {:#?}", errors); assert_eq!(errors.len(), 2); match &errors[0] { - Error::InvalidComment { msg, span } if span.line_start.get() == 2 => { + Error::InvalidComment { msg, span } if line!(span, s) == 2 => { assert!(msg.contains("must be followed by `:`")) } _ => unreachable!(), } match &errors[1] { - Error::InvalidComment { msg, span } if span.line_start.get() == 2 => { + Error::InvalidComment { msg, span } if line!(span, s) == 2 => { assert_eq!(msg, "`error-patttern` is not a command known to `ui_test`, did you mean `error-pattern`?"); } _ => unreachable!(), @@ -140,7 +151,7 @@ use std::mem; println!("parsed comments: {:#?}", errors); assert_eq!(errors.len(), 1); match &errors[0] { - Error::InvalidComment { msg, span } if span.line_start.get() == 2 => { + Error::InvalidComment { msg, span } if line!(span, s) == 2 => { assert!(msg.contains("must be followed by `:`")) } _ => unreachable!(), diff --git a/src/per_test_config.rs b/src/per_test_config.rs index 16748e66..794cbef7 100644 --- a/src/per_test_config.rs +++ b/src/per_test_config.rs @@ -368,13 +368,7 @@ impl TestConfig<'_> { if !msgs.is_empty() { let line = NonZeroUsize::new(line).expect("line 0 is always empty"); errors.push(Error::ErrorsWithoutPattern { - path: Some(Spanned::new( - self.status.path().to_path_buf(), - spanned::Span { - line_start: line, - ..spanned::Span::default() - }, - )), + path: Some((self.status.path().to_path_buf(), line)), msgs, }); } diff --git a/src/rustc_stderr.rs b/src/rustc_stderr.rs index eae180ee..17e1082d 100644 --- a/src/rustc_stderr.rs +++ b/src/rustc_stderr.rs @@ -5,7 +5,7 @@ use std::path::{Path, PathBuf}; use crate::diagnostics::{Diagnostics, Message}; -fn diag_line(diag: &Diagnostic, file: &Path) -> Option { +fn diag_line(diag: &Diagnostic, file: &Path) -> Option<(spanned::Span, usize)> { let span = |primary| { diag.spans .iter() @@ -20,20 +20,21 @@ fn insert_recursive( file: &Path, messages: &mut Vec>, messages_from_unknown_file_or_line: &mut Vec, - line: Option, + line: Option<(spanned::Span, usize)>, ) { let line = diag_line(&diag, file).or(line); let msg = Message { level: diag.level.into(), message: diag.message, - line_col: line.clone(), + line: line.as_ref().map(|&(_, l)| l), + span: line.as_ref().map(|(s, _)| s.clone()), code: diag.code.map(|x| x.code), }; - if let Some(line) = line.clone() { - if messages.len() <= line.line_start.get() { - messages.resize_with(line.line_start.get() + 1, Vec::new); + if let Some((_, line)) = line.clone() { + if messages.len() <= line { + messages.resize_with(line + 1, Vec::new); } - messages[line.line_start.get()].push(msg); + messages[line].push(msg); // All other messages go into the general bin, unless they are specifically of the // "aborting due to X previous errors" variety, as we never want to match those. They // only count the number of errors and provide no useful information about the tests. @@ -54,7 +55,7 @@ fn insert_recursive( } /// Returns the most expanded line number *in the given file*, if possible. -fn span_line(span: &DiagnosticSpan, file: &Path, primary: bool) -> Option { +fn span_line(span: &DiagnosticSpan, file: &Path, primary: bool) -> Option<(spanned::Span, usize)> { let file_name = PathBuf::from(&span.file_name); if let Some(exp) = &span.expansion { if let Some(line) = span_line(&exp.span, file, !primary || span.is_primary) { @@ -69,13 +70,14 @@ fn span_line(span: &DiagnosticSpan, file: &Path, primary: bool) -> Option { - let annot = [("expected because of this annotation", Some(span.clone()))]; - let mut lines: Vec<(&[_], _)> = vec![(&annot, span.line_start)]; - let annot = [("expected because of this mode change", Some(mode.clone()))]; + let annot = [("expected because of this annotation", span.clone())]; + let mut lines: Vec<&[_]> = vec![&annot]; + let annot = [("expected because of this mode change", mode.clone())]; if !mode.is_dummy() { - lines.push((&annot, mode.line_start)) + lines.push(&annot) } // This will print a suitable error header. create_error("error pattern found in pass test", &lines, path); @@ -619,8 +610,7 @@ fn print_error(error: &Error, path: &Path) { crate::diff::print_diff(expected, actual); } Error::ErrorsWithoutPattern { path, msgs } => { - if let Some(path) = path.as_ref() { - let line = path.line(); + if let Some((path, _)) = path.as_ref() { let msgs = msgs .iter() .map(|msg| { @@ -630,19 +620,16 @@ fn print_error(error: &Error, path: &Path) { } _ => format!("{:?}: {}", msg.level, msg.message), }; - (text, msg.line_col.clone()) + (text, msg.span.clone().unwrap_or_default()) }) .collect::>(); // This will print a suitable error header. create_error( format!("there were {} unmatched diagnostics", msgs.len()), - &[( - &msgs - .iter() - .map(|(msg, lc)| (msg.as_ref(), lc.clone().map(Into::into))) - .collect::>(), - line, - )], + &[&msgs + .iter() + .map(|(msg, lc)| (msg.as_ref(), lc.clone())) + .collect::>()], path, ); } else { @@ -653,8 +640,9 @@ fn print_error(error: &Error, path: &Path) { for Message { level, message, - line_col: _, + line: _, code: _, + span: _, } in msgs { println!(" {level:?}: {message}") @@ -663,17 +651,14 @@ fn print_error(error: &Error, path: &Path) { } Error::InvalidComment { msg, span } => { // This will print a suitable error header. - create_error(msg, &[(&[("", Some(span.clone()))], span.line_start)], path) + create_error(msg, &[&[("", span.clone())]], path) } Error::MultipleRevisionsWithResults { kind, lines } => { let title = format!("multiple {kind} found"); // This will print a suitable error header. create_error( title, - &lines - .iter() - .map(|&line| (&[] as &[_], line)) - .collect::>(), + &lines.iter().map(|_line| &[] as &[_]).collect::>(), path, ) } @@ -684,12 +669,12 @@ fn print_error(error: &Error, path: &Path) { Error::Aux { path: aux_path, errors, - line, } => { - print_error_header(format_args!( - "aux build from {}:{line} failed", - display(path) - )); + create_error( + "aux build failed", + &[&[(&path.display().to_string(), aux_path.span.clone())]], + &aux_path.span.file, + ); for error in errors { print_error(error, aux_path); } @@ -708,49 +693,32 @@ fn print_error(error: &Error, path: &Path) { } #[allow(clippy::type_complexity)] -fn create_error( - s: impl AsRef, - lines: &[(&[(&str, Option)], NonZeroUsize)], - file: &Path, -) { +fn create_error(s: impl AsRef, lines: &[&[(&str, Span)]], file: &Path) { let source = std::fs::read_to_string(file).unwrap(); - let source: Vec<_> = source.split_inclusive('\n').collect(); let file = display(file); let mut msg = annotate_snippets::Level::Error.title(s.as_ref()); - for &(label, line) in lines { - let Some(source) = source.get(line.get() - 1) else { - for (label, _) in label { - let footer = annotate_snippets::Level::Note.title(label); - msg = msg.footer(footer); - } - - continue; - }; - let len = source.len(); - let snippet = Snippet::source(source) - .line_start(line.get()) - .origin(&file) - .annotations(label.iter().map(|(label, lc)| { + for &label in lines { + let annotations = label + .iter() + .filter(|(_, span)| !span.is_dummy()) + .map(|(label, span)| { annotate_snippets::Level::Error - .span(lc.as_ref().map_or(0..len - 1, |lc| { - assert_eq!(lc.line_start, line); - if lc.line_end > lc.line_start { - lc.col_start.get() - 1..len - 1 - } else if lc.col_start == lc.col_end { - if lc.col_start.get() - 1 == len { - // rustc sometimes produces spans pointing *after* the `\n` at the end of the line, - // but we want to render an annotation at the end. - lc.col_start.get() - 2..lc.col_start.get() - 1 - } else { - lc.col_start.get() - 1..lc.col_start.get() - } - } else { - lc.col_start.get() - 1..lc.col_end.get() - 1 - } - })) + .span(span.bytes.clone()) .label(label) - })); - msg = msg.snippet(snippet); + }) + .collect::>(); + if !annotations.is_empty() { + let snippet = Snippet::source(&source) + .fold(true) + .origin(&file) + .annotations(annotations); + msg = msg.snippet(snippet); + } + let footer = label + .iter() + .filter(|(_, span)| span.is_dummy()) + .map(|(label, _)| annotate_snippets::Level::Note.title(label)); + msg = msg.footers(footer); } let renderer = if colored::control::SHOULD_COLORIZE.should_colorize() { Renderer::styled() @@ -761,6 +729,14 @@ fn create_error( } fn gha_error(error: &Error, test_path: &str, revision: &str) { + let file = Spanned::read_from_file(test_path).unwrap(); + let line = |span: &Span| { + let line = file + .lines() + .position(|line| line.span.bytes.contains(&span.bytes.start)) + .unwrap(); + NonZeroUsize::new(line + 1).unwrap() + }; match error { Error::ExitStatus { status, @@ -778,11 +754,11 @@ fn gha_error(error: &Error, test_path: &str, revision: &str) { } Error::PatternNotFound { pattern, .. } => { github_actions::error(test_path, format!("Pattern not found{revision}")) - .line(pattern.line()); + .line(line(&pattern.span)); } Error::CodeNotFound { code, .. } => { github_actions::error(test_path, format!("Diagnostic code not found{revision}")) - .line(code.line()); + .line(line(&code.span)); } Error::NoPatternsFound => { github_actions::error( @@ -862,16 +838,16 @@ fn gha_error(error: &Error, test_path: &str, revision: &str) { } } Error::ErrorsWithoutPattern { path, msgs } => { - if let Some(path) = path.as_ref() { - let line = path.line(); + if let Some((path, line)) = path.as_ref() { let path = display(path); let mut err = github_actions::error(path, format!("Unmatched diagnostics{revision}")) - .line(line); + .line(*line); for Message { level, message, - line_col: _, + line: _, + span: _, code: _, } in msgs { @@ -885,7 +861,8 @@ fn gha_error(error: &Error, test_path: &str, revision: &str) { for Message { level, message, - line_col: _, + line: _, + span: _, code: _, } in msgs { @@ -895,19 +872,20 @@ fn gha_error(error: &Error, test_path: &str, revision: &str) { } Error::InvalidComment { msg, span } => { let mut err = github_actions::error(test_path, format!("Could not parse comment")) - .line(span.line_start); + .line(line(span)); writeln!(err, "{msg}").unwrap(); } Error::MultipleRevisionsWithResults { kind, lines } => { - github_actions::error(test_path, format!("multiple {kind} found")).line(lines[0]); + github_actions::error(test_path, format!("multiple {kind} found")) + .line(line(&lines[0])); } Error::Bug(_) => {} Error::Aux { path: aux_path, errors, - line, } => { - github_actions::error(test_path, format!("Aux build failed")).line(*line); + github_actions::error(test_path, format!("Aux build failed")) + .line(line(&aux_path.span)); for error in errors { gha_error(error, &display(aux_path), "") } diff --git a/src/tests.rs b/src/tests.rs index feaaf041..59a27bfa 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -32,6 +32,17 @@ macro_rules! config { }; } +macro_rules! line { + ($thing:expr, $s:expr) => {{ + let file = Spanned::dummy($s.as_bytes()); + let pos = file + .lines() + .position(|line| line.span.bytes.contains(&$thing.bytes.start)) + .unwrap(); + pos + }}; +} + #[test] fn issue_2156() { let s = r" @@ -50,7 +61,8 @@ fn main() { Message { message:"Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -60,7 +72,8 @@ fn main() { .unwrap(); match &errors[..] { [Error::PatternNotFound { pattern, .. }, Error::ErrorsWithoutPattern { path, .. }] - if path.as_ref().is_some_and(|p| p.line().get() == 5) && pattern.line().get() == 5 => {} + if path.as_ref().is_some_and(|(_p, line)| line.get() == 5) + && line!(pattern.span, s) == 5 => {} _ => panic!("{:#?}", errors), } } @@ -81,7 +94,8 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -102,7 +116,8 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -113,8 +128,8 @@ fn main() { .unwrap(); match &errors[..] { [Error::PatternNotFound { pattern, .. }, Error::ErrorsWithoutPattern { path, .. }] - if path.as_ref().is_some_and(|p| p.line().get() == 4) - && pattern.line().get() == 5 => {} + if path.as_ref().is_some_and(|(_, line)| line.get() == 4) + && line!(pattern.span, s) == 5 => {} _ => panic!("not the expected error: {:#?}", errors), } } @@ -127,7 +142,8 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Note, - line_col: None, + line: None, + span: None, code: None, } ] @@ -138,7 +154,7 @@ fn main() { .unwrap(); match &errors[..] { // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them - [Error::PatternNotFound { pattern, .. }] if pattern.line().get() == 5 => {} + [Error::PatternNotFound { pattern, .. }] if line!(pattern.span, s) == 5 => {} _ => panic!("not the expected error: {:#?}", errors), } } @@ -162,7 +178,8 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -172,7 +189,7 @@ fn main() { .check_annotations(messages, vec![], &mut errors) .unwrap(); match &errors[..] { - [Error::PatternNotFound { pattern, .. }] if pattern.line().get() == 6 => {} + [Error::PatternNotFound { pattern, .. }] if line!(pattern.span, s) == 6 => {} _ => panic!("{:#?}", errors), } } @@ -194,13 +211,15 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, } ] @@ -211,7 +230,7 @@ fn main() { .unwrap(); match &errors[..] { [Error::ErrorsWithoutPattern { path, .. }] - if path.as_ref().is_some_and(|p| p.line().get() == 5) => {} + if path.as_ref().is_some_and(|(_, line)| line.get() == 5) => {} _ => panic!("{:#?}", errors), } } @@ -238,19 +257,22 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "kaboom".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "cake".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: None, }, ], @@ -261,13 +283,14 @@ fn main() { .unwrap(); match &errors[..] { [Error::ErrorsWithoutPattern { path, msgs, .. }] - if path.as_ref().is_some_and(|p| p.line().get() == 5) => + if path.as_ref().is_some_and(|(_, line)| line.get() == 5) => { match &msgs[..] { [Message { message, level: Level::Warn, - line_col: _, + line: _, + span: _, code: None, }] if message == "kaboom" => {} _ => panic!("{:#?}", msgs), @@ -299,19 +322,22 @@ fn main() { Message { message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "kaboom".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: None, }, Message { message: "cake".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: None, }, ], @@ -343,7 +369,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: Some("E0308".into()), }], ]; @@ -366,7 +393,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: Some("SomeError".into()), }], ]; @@ -376,7 +404,7 @@ fn main() { .unwrap(); match &errors[..] { [Error::CodeNotFound { code, .. }, Error::ErrorsWithoutPattern { msgs, .. }] - if **code == "E0308" && code.line().get() == 3 && msgs.len() == 1 => {} + if **code == "E0308" && line!(code.span, s) == 3 && msgs.len() == 1 => {} _ => panic!("{:#?}", errors), } } @@ -390,7 +418,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Warn, - line_col: None, + line: None, + span: None, code: Some("E0308".into()), }], ]; @@ -399,7 +428,8 @@ fn main() { .check_annotations(messages, vec![], &mut errors) .unwrap(); match &errors[..] { - [Error::CodeNotFound { code, .. }] if **code == "E0308" && code.line().get() == 3 => {} + [Error::CodeNotFound { code, .. }] if **code == "E0308" && line!(code.span, s) == 3 => { + } _ => panic!("{:#?}", errors), } } @@ -424,7 +454,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: Some("prefix::E0308".into()), }], ]; @@ -447,7 +478,8 @@ fn main() { vec![Message { message: "mismatched types".to_string(), level: Level::Error, - line_col: None, + line: None, + span: None, code: Some("E0308".into()), }], ]; @@ -457,7 +489,7 @@ fn main() { .unwrap(); match &errors[..] { [Error::CodeNotFound { code, .. }, Error::ErrorsWithoutPattern { msgs, .. }] - if **code == "prefix::E0308" && code.line().get() == 3 && msgs.len() == 1 => {} + if **code == "prefix::E0308" && line!(code.span, s) == 3 && msgs.len() == 1 => {} _ => panic!("{:#?}", errors), } } diff --git a/tests/integrations/basic-bin/Cargo.lock b/tests/integrations/basic-bin/Cargo.lock index 1207fc73..71bc833f 100644 --- a/tests/integrations/basic-bin/Cargo.lock +++ b/tests/integrations/basic-bin/Cargo.lock @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -716,7 +716,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/basic-fail-mode/Cargo.lock b/tests/integrations/basic-fail-mode/Cargo.lock index fbf8cdec..a1c4d89d 100644 --- a/tests/integrations/basic-fail-mode/Cargo.lock +++ b/tests/integrations/basic-fail-mode/Cargo.lock @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -716,7 +716,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/basic-fail/Cargo.lock b/tests/integrations/basic-fail/Cargo.lock index a0962282..1c0e9dbb 100644 --- a/tests/integrations/basic-fail/Cargo.lock +++ b/tests/integrations/basic-fail/Cargo.lock @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -716,7 +716,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/basic-fail/Cargo.stdout b/tests/integrations/basic-fail/Cargo.stdout index c7162fb5..39e6499f 100644 --- a/tests/integrations/basic-fail/Cargo.stdout +++ b/tests/integrations/basic-fail/Cargo.stdout @@ -504,6 +504,7 @@ tests/actual_tests_bless/rustfix-fail-revisions.b.fixed (revision `b`) ... FAILE tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `b`) ... ok tests/actual_tests_bless/rustfix-fail.fixed ... FAILED tests/actual_tests_bless/rustfix-fail.rs ... ok +tests/actual_tests_bless/unicode.rs ... FAILED tests/actual_tests_bless/unknown_revision.rs ... FAILED tests/actual_tests_bless/unknown_revision2.rs ... FAILED tests/actual_tests_bless/wrong_diagnostic_code.rs ... FAILED @@ -637,7 +638,7 @@ error: test got exit status: 101, but expected 0 --> tests/actual_tests_bless/failing_executable.rs:4:5 | 4 | assert_eq!(5, 6); - | ^ assertion `left == right` failed + | ^^^^^^^^^^^^^^^^^ assertion `left == right` failed | full stderr: @@ -801,7 +802,7 @@ error: test got exit status: 101, but expected 0 --> tests/actual_tests_bless/revisioned_executable_panic.rs | 6 | panic!() - | ^ explicit panic + | ^^^^^^^^ explicit panic | full stderr: @@ -938,6 +939,38 @@ full stdout: +FAILED TEST: tests/actual_tests_bless/unicode.rs +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/unicode.rs" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail.rlib" "--extern" "basic_fail=$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug/libbasic_fail-$HASH.rmeta" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "-L" "$DIR/tests/integrations/basic-fail/../../../target/$TMP/$TRIPLE/debug" "--edition" "2021" + +error: test got exit status: 0, but expected 1 + = note: compilation succeeded, but was expected to fail + +error: expected error patterns, but found none + +full stderr: +warning: unused variable: `Ě电脑` + --> tests/actual_tests_bless/unicode.rs:7:9 + | +7 | let Ě电脑 = 1; + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_Ě电脑` + | + = note: `#[warn(unused_variables)]` on by default + +warning: variable `Ě电脑` should have a snake case name + --> tests/actual_tests_bless/unicode.rs:7:9 + | +7 | let Ě电脑 = 1; + | ^^^^^ help: convert the identifier to snake case: `ě电脑` + | + = note: `#[warn(non_snake_case)]` on by default + +warning: 2 warnings emitted + + +full stdout: + + + FAILED TEST: tests/actual_tests_bless/unknown_revision.rs command: parse comments @@ -1040,11 +1073,12 @@ FAILURES: tests/actual_tests_bless/rustfix-fail-revisions.a.fixed (revision a) tests/actual_tests_bless/rustfix-fail-revisions.b.fixed (revision b) tests/actual_tests_bless/rustfix-fail.fixed + tests/actual_tests_bless/unicode.rs tests/actual_tests_bless/unknown_revision.rs tests/actual_tests_bless/unknown_revision2.rs tests/actual_tests_bless/wrong_diagnostic_code.rs -test result: FAIL. 22 failed; 24 passed; 3 ignored; +test result: FAIL. 23 failed; 24 passed; 3 ignored; Building dependencies ... ok tests/actual_tests_bless_yolo/revisions_bad.rs (revision `foo`) ... ok diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.rs b/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.rs new file mode 100644 index 00000000..d9e54ab5 --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.rs @@ -0,0 +1,8 @@ +#![deny(confusable_idents)] + +// Test that a missing annotation causing a +// ui_test diagnostic will not ICE due to byte vs char offsets. + +fn main() { + let Ě电脑 = 1; +} diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.stderr b/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.stderr new file mode 100644 index 00000000..b92bcd9e --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless/unicode.stderr @@ -0,0 +1,18 @@ +warning: unused variable: `Ě电脑` + --> tests/actual_tests_bless/unicode.rs:7:9 + | +7 | let Ě电脑 = 1; + | ^^^^^ help: if this is intentional, prefix it with an underscore: `_Ě电脑` + | + = note: `#[warn(unused_variables)]` on by default + +warning: variable `Ě电脑` should have a snake case name + --> tests/actual_tests_bless/unicode.rs:7:9 + | +7 | let Ě电脑 = 1; + | ^^^^^ help: convert the identifier to snake case: `ě电脑` + | + = note: `#[warn(non_snake_case)]` on by default + +warning: 2 warnings emitted + diff --git a/tests/integrations/basic/Cargo.lock b/tests/integrations/basic/Cargo.lock index 85fbb093..1039bba3 100644 --- a/tests/integrations/basic/Cargo.lock +++ b/tests/integrations/basic/Cargo.lock @@ -522,9 +522,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -639,7 +639,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/cargo-run/Cargo.lock b/tests/integrations/cargo-run/Cargo.lock index 1207fc73..71bc833f 100644 --- a/tests/integrations/cargo-run/Cargo.lock +++ b/tests/integrations/cargo-run/Cargo.lock @@ -597,9 +597,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -716,7 +716,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/dep-fail/Cargo.lock b/tests/integrations/dep-fail/Cargo.lock index 5f392a44..f90b0357 100644 --- a/tests/integrations/dep-fail/Cargo.lock +++ b/tests/integrations/dep-fail/Cargo.lock @@ -461,9 +461,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -565,7 +565,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow", diff --git a/tests/integrations/ui_test_dep_bug/Cargo.lock b/tests/integrations/ui_test_dep_bug/Cargo.lock index 1d8cb9ee..0e51e6ce 100644 --- a/tests/integrations/ui_test_dep_bug/Cargo.lock +++ b/tests/integrations/ui_test_dep_bug/Cargo.lock @@ -462,9 +462,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" +checksum = "86af297923fbcfd107c20a189a6e9c872160df71a7190ae4a7a6c5dce4b2feb6" dependencies = [ "bstr", "color-eyre", @@ -570,7 +570,7 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.24.0" +version = "0.25.0" dependencies = [ "annotate-snippets", "anyhow",