From 482e3d9229ac915f4eeea3cf6dd30ed1181af7f4 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Thu, 4 Jul 2024 19:58:14 +0000 Subject: [PATCH 1/3] Move some rustfix code into separate functions --- src/custom_flags/rustfix.rs | 239 +++++++++++++++++++----------------- 1 file changed, 126 insertions(+), 113 deletions(-) diff --git a/src/custom_flags/rustfix.rs b/src/custom_flags/rustfix.rs index 21b5b03..2494f3c 100644 --- a/src/custom_flags/rustfix.rs +++ b/src/custom_flags/rustfix.rs @@ -2,6 +2,7 @@ use std::{ collections::HashSet, + path::Path, process::{Command, Output}, }; @@ -57,79 +58,15 @@ impl Flag for RustfixMode { }; let output = output.clone(); let no_run_rustfix = config.find_one_custom("no-rustfix")?; - let fixed_code = (no_run_rustfix.is_none() && global_rustfix.enabled()) - .then_some(()) - .and_then(|()| { - let suggestions = std::str::from_utf8(&output.stderr) - .unwrap() - .lines() - .flat_map(|line| { - if !line.starts_with('{') { - return vec![]; - } - rustfix::get_suggestions_from_json( - line, - &HashSet::new(), - if global_rustfix == RustfixMode::Everything { - rustfix::Filter::Everything - } else { - rustfix::Filter::MachineApplicableOnly - }, - ) - .unwrap_or_else(|err| { - panic!("could not deserialize diagnostics json for rustfix {err}:{line}") - }) - }) - .collect::>(); - if suggestions.is_empty() { - None - } else { - let path_str = display(config.status.path()); - for sugg in &suggestions { - for snip in &sugg.snippets { - let file_name = snip.file_name.replace('\\', "/"); - if file_name != path_str { - return Some(Err(anyhow::anyhow!("cannot apply suggestions for `{file_name}` since main file is `{path_str}`. Please use `//@no-rustfix` to disable rustfix"))); - } - } - } - Some(rustfix::apply_suggestions( - &std::fs::read_to_string(config.status.path()).unwrap(), - &suggestions, - ).map_err(|e| e.into())) - } - }) - .transpose() - .map_err(|err| Errored { + let fixed_code = if no_run_rustfix.is_none() && global_rustfix.enabled() { + fix(&output.stderr, config.status.path(), global_rustfix).map_err(|err| Errored { command: format!("rustfix {}", display(config.status.path())), errors: vec![Error::Rustfix(err)], stderr: output.stderr, stdout: output.stdout, - })?; - - let rustfix_comments = Comments { - revisions: None, - revisioned: std::iter::once(( - vec![], - Revisioned { - span: Span::default(), - ignore: vec![], - only: vec![], - stderr_per_bitwidth: false, - compile_flags: config.collect(|r| r.compile_flags.iter().cloned()), - env_vars: config.collect(|r| r.env_vars.iter().cloned()), - normalize_stderr: vec![], - normalize_stdout: vec![], - error_in_other_files: vec![], - error_matches: vec![], - require_annotations_for_level: Default::default(), - diagnostic_code_prefix: OptWithLine::new(String::new(), Span::default()), - custom: config.comments().flat_map(|r| r.custom.clone()).collect(), - exit_status: OptWithLine::new(0, Span::default()), - require_annotations: OptWithLine::default(), - }, - )) - .collect(), + })? + } else { + None }; let run = fixed_code.is_some(); @@ -141,16 +78,6 @@ impl Flag for RustfixMode { &mut errors, "fixed", ); - // picking the crate name from the file name is problematic when `.revision_name` is inserted, - // so we compute it here before replacing the path. - let crate_name = config - .status - .path() - .file_stem() - .unwrap() - .to_str() - .unwrap() - .replace('-', "_"); if !errors.is_empty() { return Ok(Some(TestRun { @@ -168,42 +95,128 @@ impl Flag for RustfixMode { return Ok(None); } - let config = TestConfig { - config: config.config.clone(), - comments: &rustfix_comments, - aux_dir: config.aux_dir, - status: config.status.for_path(&rustfix_path), - }; + compile_fixed(config, build_manager, &rustfix_path) + } +} - let mut cmd = config.build_command(build_manager)?; - cmd.arg("--crate-name").arg(crate_name); - let output = cmd.output().unwrap(); - if output.status.success() { - Ok(Some(TestRun { - result: Ok(TestOk::Ok), - status: config.status, - })) - } else { - let diagnostics = config.process(&output.stderr); - Err(Errored { - command: format!("{cmd:?}"), - errors: vec![Error::ExitStatus { - expected: 0, - status: output.status, - reason: Spanned::new( - "after rustfix is applied, all errors should be gone, but weren't".into(), - diagnostics - .messages - .iter() - .flatten() - .chain(diagnostics.messages_from_unknown_file_or_line.iter()) - .find_map(|message| message.line_col.clone()) - .unwrap_or_default(), - ), - }], - stderr: diagnostics.rendered, - stdout: output.stdout, +fn fix(stderr: &[u8], path: &Path, global_rustfix: RustfixMode) -> anyhow::Result> { + let suggestions = std::str::from_utf8(stderr) + .unwrap() + .lines() + .flat_map(|line| { + if !line.starts_with('{') { + return vec![]; + } + rustfix::get_suggestions_from_json( + line, + &HashSet::new(), + if global_rustfix == RustfixMode::Everything { + rustfix::Filter::Everything + } else { + rustfix::Filter::MachineApplicableOnly + }, + ) + .unwrap_or_else(|err| { + panic!("could not deserialize diagnostics json for rustfix {err}:{line}") }) + }) + .collect::>(); + if suggestions.is_empty() { + Ok(None) + } else { + let path_str = display(path); + for sugg in &suggestions { + for snip in &sugg.snippets { + let file_name = snip.file_name.replace('\\', "/"); + anyhow::ensure!( + file_name == path_str, + "cannot apply suggestions for `{file_name}` since main file is `{path_str}`. Please use `//@no-rustfix` to disable rustfix", + ) + } } + Ok(Some(rustfix::apply_suggestions( + &std::fs::read_to_string(path).unwrap(), + &suggestions, + )?)) + } +} + +fn compile_fixed( + config: &TestConfig, + build_manager: &BuildManager<'_>, + rustfix_path: &Path, +) -> Result, Errored> { + // picking the crate name from the file name is problematic when `.revision_name` is inserted, + // so we compute it here before replacing the path. + let crate_name = config + .status + .path() + .file_stem() + .unwrap() + .to_str() + .unwrap() + .replace('-', "_"); + + let rustfix_comments = Comments { + revisions: None, + revisioned: std::iter::once(( + vec![], + Revisioned { + span: Span::default(), + ignore: vec![], + only: vec![], + stderr_per_bitwidth: false, + compile_flags: config.collect(|r| r.compile_flags.iter().cloned()), + env_vars: config.collect(|r| r.env_vars.iter().cloned()), + normalize_stderr: vec![], + normalize_stdout: vec![], + error_in_other_files: vec![], + error_matches: vec![], + require_annotations_for_level: Default::default(), + diagnostic_code_prefix: OptWithLine::new(String::new(), Span::default()), + custom: config.comments().flat_map(|r| r.custom.clone()).collect(), + exit_status: OptWithLine::new(0, Span::default()), + require_annotations: OptWithLine::default(), + }, + )) + .collect(), + }; + + let fixed_config = TestConfig { + config: config.config.clone(), + comments: &rustfix_comments, + aux_dir: config.aux_dir, + status: config.status.for_path(&rustfix_path), + }; + + let mut cmd = fixed_config.build_command(build_manager)?; + cmd.arg("--crate-name").arg(crate_name); + let output = cmd.output().unwrap(); + if output.status.success() { + Ok(Some(TestRun { + result: Ok(TestOk::Ok), + status: fixed_config.status, + })) + } else { + let diagnostics = fixed_config.process(&output.stderr); + Err(Errored { + command: format!("{cmd:?}"), + errors: vec![Error::ExitStatus { + expected: 0, + status: output.status, + reason: Spanned::new( + "after rustfix is applied, all errors should be gone, but weren't".into(), + diagnostics + .messages + .iter() + .flatten() + .chain(diagnostics.messages_from_unknown_file_or_line.iter()) + .find_map(|message| message.line_col.clone()) + .unwrap_or_default(), + ), + }], + stderr: diagnostics.rendered, + stdout: output.stdout, + }) } } From 97555c3ff3daa7f0de9ff92f279ab17061de50f0 Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 5 Jul 2024 01:35:57 +0000 Subject: [PATCH 2/3] Fix incomplete progress bar assertions when panicking --- src/status_emitter.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/status_emitter.rs b/src/status_emitter.rs index a37f69e..e64dd3d 100644 --- a/src/status_emitter.rs +++ b/src/status_emitter.rs @@ -232,9 +232,10 @@ impl Text { Msg::Inc => { progress.as_ref().unwrap().inc(1); } - Msg::Finish => return, + Msg::Finish => break 'outer, }, - Err(TryRecvError::Disconnected) => break 'outer, + // Sender panicked, skip asserts + Err(TryRecvError::Disconnected) => return, Err(TryRecvError::Empty) => break, } } @@ -245,7 +246,7 @@ impl Text { progress.tick() } } - assert_eq!(threads.len(), 0); + assert_eq!(threads.len(), 0, "remaining: {threads:?}"); if let Some(progress) = progress { progress.tick(); assert!(progress.is_finished()); @@ -323,9 +324,8 @@ impl TestStatus for TextTest { if ProgressDrawTarget::stdout().is_hidden() { println!("{old_msg} {msg}"); std::io::stdout().flush().unwrap(); - } else { - self.text.sender.send(Msg::Pop(old_msg, Some(msg))).unwrap(); } + self.text.sender.send(Msg::Pop(old_msg, Some(msg))).unwrap(); } } From 7ec0bc7da062f00dafa4344203c5f40610d0566e Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Fri, 5 Jul 2024 02:06:37 +0000 Subject: [PATCH 3/3] Create multiple .fixed files for diagnostics with multiple suggestions --- CHANGELOG.md | 1 + src/custom_flags.rs | 6 +- src/custom_flags/run.rs | 11 +- src/custom_flags/rustfix.rs | 212 ++++++++++-------- src/per_test_config.rs | 22 +- tests/integrations/basic-fail/Cargo.stdout | 74 ++++-- .../rustfix-multiple-fail.1.fixed | 8 + .../rustfix-multiple-fail.2.fixed | 8 + .../rustfix-multiple-fail.3.fixed | 8 + .../rustfix-multiple-fail.rs | 8 + .../rustfix-multiple-fail.stderr | 24 ++ .../basic-fail/tests/ui_tests_bless.rs | 7 +- tests/integrations/basic/Cargo.stdout | 5 +- .../actual_tests/rustfix-multiple.1.fixed | 9 + .../actual_tests/rustfix-multiple.2.fixed | 9 + .../tests/actual_tests/rustfix-multiple.rs | 9 + .../actual_tests/rustfix-multiple.stderr | 18 ++ 17 files changed, 303 insertions(+), 136 deletions(-) create mode 100644 tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.1.fixed create mode 100644 tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed create mode 100644 tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.3.fixed create mode 100644 tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.rs create mode 100644 tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.stderr create mode 100644 tests/integrations/basic/tests/actual_tests/rustfix-multiple.1.fixed create mode 100644 tests/integrations/basic/tests/actual_tests/rustfix-multiple.2.fixed create mode 100644 tests/integrations/basic/tests/actual_tests/rustfix-multiple.rs create mode 100644 tests/integrations/basic/tests/actual_tests/rustfix-multiple.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f47f0f..3c570f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Split up `Revisioned::mode` into `Revisioned::exit_status` and `Revisioned::require_annotations` * `Config::output_conflict_handling` is now `Error` instead of `Bless` +* Rustfix tests now create multiple `.fixed` files if diagnostics contain multiple suggestions * updated `prettydiff` from 0.6.4 to 0.7.0, which drops `ansi_term` and `winapi*` deps. ### Removed diff --git a/src/custom_flags.rs b/src/custom_flags.rs index d2fc43d..e75ed4e 100644 --- a/src/custom_flags.rs +++ b/src/custom_flags.rs @@ -34,15 +34,15 @@ pub trait Flag: Send + Sync + UnwindSafe + RefUnwindSafe + std::fmt::Debug { } /// Run an action after a test is finished. - /// Returns `None` if no action was taken. + /// Returns an empty [`Vec`] if no action was taken. fn post_test_action( &self, _config: &TestConfig<'_>, _cmd: &mut Command, _output: &Output, _build_manager: &BuildManager<'_>, - ) -> Result, Errored> { - Ok(None) + ) -> Result, Errored> { + Ok(Vec::new()) } /// Whether the flag gets overridden by the same flag in revisions. diff --git a/src/custom_flags/run.rs b/src/custom_flags/run.rs index 1637b5e..98af12f 100644 --- a/src/custom_flags/run.rs +++ b/src/custom_flags/run.rs @@ -8,8 +8,8 @@ use std::{ }; use crate::{ - build_manager::BuildManager, display, per_test_config::TestConfig, test_result::TestRun, Error, - Errored, TestOk, + build_manager::BuildManager, display, per_test_config::TestConfig, Error, Errored, TestOk, + TestRun, }; use super::Flag; @@ -33,7 +33,7 @@ impl Flag for Run { cmd: &mut Command, _output: &Output, _build_manager: &BuildManager<'_>, - ) -> Result, Errored> { + ) -> Result, Errored> { let exit_code = self.exit_code; let revision = config.extension("run"); let config = TestConfig { @@ -80,7 +80,8 @@ impl Flag for Run { }, }) } - Ok(Some(TestRun { + + Ok(vec![TestRun { result: if errors.is_empty() { Ok(TestOk::Ok) } else { @@ -92,7 +93,7 @@ impl Flag for Run { }) }, status: config.status, - })) + }]) } } diff --git a/src/custom_flags/rustfix.rs b/src/custom_flags/rustfix.rs index 2494f3c..371c94b 100644 --- a/src/custom_flags/rustfix.rs +++ b/src/custom_flags/rustfix.rs @@ -2,10 +2,11 @@ use std::{ collections::HashSet, - path::Path, + path::{Path, PathBuf}, process::{Command, Output}, }; +use rustfix::{CodeFix, Filter, Suggestion}; use spanned::{Span, Spanned}; use crate::{ @@ -13,8 +14,7 @@ use crate::{ display, parser::OptWithLine, per_test_config::{Comments, Revisioned, TestConfig}, - test_result::TestRun, - Error, Errored, TestOk, + Error, Errored, TestOk, TestRun, }; use super::Flag; @@ -49,7 +49,7 @@ impl Flag for RustfixMode { _cmd: &mut Command, output: &Output, build_manager: &BuildManager<'_>, - ) -> Result, Errored> { + ) -> Result, Errored> { let global_rustfix = match config.exit_status()? { Some(Spanned { content: 101 | 0, .. @@ -58,7 +58,7 @@ impl Flag for RustfixMode { }; let output = output.clone(); let no_run_rustfix = config.find_one_custom("no-rustfix")?; - let fixed_code = if no_run_rustfix.is_none() && global_rustfix.enabled() { + let fixes = if no_run_rustfix.is_none() && global_rustfix.enabled() { fix(&output.stderr, config.status.path(), global_rustfix).map_err(|err| Errored { command: format!("rustfix {}", display(config.status.path())), errors: vec![Error::Rustfix(err)], @@ -66,86 +66,111 @@ impl Flag for RustfixMode { stdout: output.stdout, })? } else { - None + Vec::new() }; - let run = fixed_code.is_some(); - let mut errors = vec![]; - let rustfix_path = config.check_output( - // Always check for `.fixed` files, even if there were reasons not to run rustfix. - // We don't want to leave around stray `.fixed` files - fixed_code.unwrap_or_default().as_bytes(), - &mut errors, - "fixed", - ); + let mut errors = Vec::new(); + let fixed_paths = match fixes.as_slice() { + [] => Vec::new(), + [single] => { + vec![config.check_output(single.as_bytes(), &mut errors, "fixed")] + } + _ => fixes + .iter() + .enumerate() + .map(|(i, fix)| { + config.check_output(fix.as_bytes(), &mut errors, &format!("{}.fixed", i + 1)) + }) + .collect(), + }; - if !errors.is_empty() { - return Ok(Some(TestRun { - result: Err(Errored { - command: format!("checking {}", display(config.status.path())), - errors, - stderr: vec![], - stdout: vec![], - }), - status: config.status.for_path(&rustfix_path), - })); + if fixes.len() != 1 { + // Remove an unused .fixed file + config.check_output(&[], &mut errors, "fixed"); } - if !run { - return Ok(None); + if !errors.is_empty() { + return Err(Errored { + command: format!("checking {}", display(config.status.path())), + errors, + stderr: vec![], + stdout: vec![], + }); } - compile_fixed(config, build_manager, &rustfix_path) + compile_fixed(config, build_manager, fixed_paths) } } -fn fix(stderr: &[u8], path: &Path, global_rustfix: RustfixMode) -> anyhow::Result> { +fn fix(stderr: &[u8], path: &Path, mode: RustfixMode) -> anyhow::Result> { let suggestions = std::str::from_utf8(stderr) .unwrap() .lines() - .flat_map(|line| { + .filter_map(|line| { if !line.starts_with('{') { - return vec![]; + return None; } - rustfix::get_suggestions_from_json( - line, + let diagnostic = serde_json::from_str(line).unwrap_or_else(|err| { + panic!("could not deserialize diagnostics json for rustfix {err}:{line}") + }); + rustfix::collect_suggestions( + &diagnostic, &HashSet::new(), - if global_rustfix == RustfixMode::Everything { - rustfix::Filter::Everything + if mode == RustfixMode::Everything { + Filter::Everything } else { - rustfix::Filter::MachineApplicableOnly + Filter::MachineApplicableOnly }, ) - .unwrap_or_else(|err| { - panic!("could not deserialize diagnostics json for rustfix {err}:{line}") - }) }) .collect::>(); if suggestions.is_empty() { - Ok(None) - } else { - let path_str = display(path); - for sugg in &suggestions { - for snip in &sugg.snippets { - let file_name = snip.file_name.replace('\\', "/"); - anyhow::ensure!( - file_name == path_str, - "cannot apply suggestions for `{file_name}` since main file is `{path_str}`. Please use `//@no-rustfix` to disable rustfix", - ) - } + return Ok(Vec::new()); + } + + let max_solutions = suggestions + .iter() + .map(|suggestion| suggestion.solutions.len()) + .max() + .unwrap(); + let src = std::fs::read_to_string(path).unwrap(); + let mut fixes = (0..max_solutions) + .map(|_| CodeFix::new(&src)) + .collect::>(); + for Suggestion { + message, + snippets, + solutions, + } in suggestions + { + for snippet in &snippets { + anyhow::ensure!( + Path::new(&snippet.file_name) == path, + "cannot apply suggestions for `{}` since main file is `{}`. Please use `//@no-rustfix` to disable rustfix", + snippet.file_name, + path.display() + ); + } + + let repeat_first = std::iter::from_fn(|| solutions.first()); + for (solution, fix) in solutions.iter().chain(repeat_first).zip(&mut fixes) { + // TODO: use CodeFix::apply_solution when rustfix 0.8.5 is published + fix.apply(&Suggestion { + solutions: vec![solution.clone()], + message: message.clone(), + snippets: snippets.clone(), + })?; } - Ok(Some(rustfix::apply_suggestions( - &std::fs::read_to_string(path).unwrap(), - &suggestions, - )?)) } + + fixes.into_iter().map(|fix| Ok(fix.finish()?)).collect() } fn compile_fixed( config: &TestConfig, build_manager: &BuildManager<'_>, - rustfix_path: &Path, -) -> Result, Errored> { + fixed_paths: Vec, +) -> Result, Errored> { // picking the crate name from the file name is problematic when `.revision_name` is inserted, // so we compute it here before replacing the path. let crate_name = config @@ -182,41 +207,46 @@ fn compile_fixed( .collect(), }; - let fixed_config = TestConfig { - config: config.config.clone(), - comments: &rustfix_comments, - aux_dir: config.aux_dir, - status: config.status.for_path(&rustfix_path), - }; - - let mut cmd = fixed_config.build_command(build_manager)?; - cmd.arg("--crate-name").arg(crate_name); - let output = cmd.output().unwrap(); - if output.status.success() { - Ok(Some(TestRun { - result: Ok(TestOk::Ok), + let mut runs = Vec::new(); + for fixed_path in fixed_paths { + let fixed_config = TestConfig { + config: config.config.clone(), + comments: &rustfix_comments, + aux_dir: config.aux_dir, + status: config.status.for_path(&fixed_path), + }; + let mut cmd = fixed_config.build_command(build_manager)?; + cmd.arg("--crate-name").arg(&crate_name); + let output = cmd.output().unwrap(); + let result = if output.status.success() { + Ok(TestOk::Ok) + } else { + let diagnostics = fixed_config.process(&output.stderr); + Err(Errored { + command: format!("{cmd:?}"), + errors: vec![Error::ExitStatus { + expected: 0, + status: output.status, + reason: Spanned::new( + "after rustfix is applied, all errors should be gone, but weren't".into(), + diagnostics + .messages + .iter() + .flatten() + .chain(diagnostics.messages_from_unknown_file_or_line.iter()) + .find_map(|message| message.line_col.clone()) + .unwrap_or_default(), + ), + }], + stderr: diagnostics.rendered, + stdout: output.stdout, + }) + }; + runs.push(TestRun { + result, status: fixed_config.status, - })) - } else { - let diagnostics = fixed_config.process(&output.stderr); - Err(Errored { - command: format!("{cmd:?}"), - errors: vec![Error::ExitStatus { - expected: 0, - status: output.status, - reason: Spanned::new( - "after rustfix is applied, all errors should be gone, but weren't".into(), - diagnostics - .messages - .iter() - .flatten() - .chain(diagnostics.messages_from_unknown_file_or_line.iter()) - .find_map(|message| message.line_col.clone()) - .unwrap_or_default(), - ), - }], - stderr: diagnostics.rendered, - stdout: output.stdout, - }) + }); } + + Ok(runs) } diff --git a/src/per_test_config.rs b/src/per_test_config.rs index 099a1f9..16748e6 100644 --- a/src/per_test_config.rs +++ b/src/per_test_config.rs @@ -18,8 +18,8 @@ use crate::diagnostics::{Diagnostics, Message}; pub use crate::parser::{Comments, Condition, Revisioned}; use crate::parser::{ErrorMatch, ErrorMatchKind, OptWithLine}; use crate::status_emitter::TestStatus; -use crate::test_result::{Errored, TestOk, TestResult, TestRun}; -use crate::{core::strip_path_prefix, Config, Error, Errors, OutputConflictHandling}; +use crate::test_result::{Errored, TestOk, TestResult}; +use crate::{core::strip_path_prefix, Config, Error, Errors, OutputConflictHandling, TestRun}; /// All information needed to run a single test pub struct TestConfig<'a> { @@ -162,11 +162,11 @@ impl TestConfig<'_> { self.status.path().with_extension(ext) } - pub(crate) fn normalize(&self, text: &[u8], kind: &'static str) -> Vec { + pub(crate) fn normalize(&self, text: &[u8], kind: &str) -> Vec { let mut text = text.to_owned(); for (from, to) in self.comments().flat_map(|r| match kind { - "fixed" => &[] as &[_], + _ if kind.ends_with("fixed") => &[] as &[_], "stderr" => &r.normalize_stderr, "stdout" => &r.normalize_stdout, _ => unreachable!(), @@ -183,12 +183,7 @@ impl TestConfig<'_> { self.check_output(stdout, errors, "stdout"); } - pub(crate) fn check_output( - &self, - output: &[u8], - errors: &mut Errors, - kind: &'static str, - ) -> PathBuf { + pub(crate) fn check_output(&self, output: &[u8], errors: &mut Errors, kind: &str) -> PathBuf { let output = self.normalize(output, kind); let path = self.output_path(kind); match &self.config.output_conflict_handling { @@ -420,12 +415,7 @@ impl TestConfig<'_> { for rev in self.comments() { for custom in rev.custom.values() { for flag in &custom.content { - if let Some(result) = - flag.post_test_action(self, &mut cmd, &output, build_manager)? - { - runs.push(result); - return Ok(TestOk::Ok); - } + runs.extend(flag.post_test_action(self, &mut cmd, &output, build_manager)?); } } } diff --git a/tests/integrations/basic-fail/Cargo.stdout b/tests/integrations/basic-fail/Cargo.stdout index 43ab34d..c7162fb 100644 --- a/tests/integrations/basic-fail/Cargo.stdout +++ b/tests/integrations/basic-fail/Cargo.stdout @@ -498,9 +498,12 @@ tests/actual_tests_bless/revisions_same_everywhere.rs (revision `foo`) ... ok tests/actual_tests_bless/revisions_same_everywhere.rs (revision `bar`) ... ok tests/actual_tests_bless/run_panic.rs (revision `run`) ... ok tests/actual_tests_bless/run_panic.rs ... ok -tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `a`) ... FAILED -tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `b`) ... FAILED -tests/actual_tests_bless/rustfix-fail.rs ... FAILED +tests/actual_tests_bless/rustfix-fail-revisions.a.fixed (revision `a`) ... FAILED +tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `a`) ... ok +tests/actual_tests_bless/rustfix-fail-revisions.b.fixed (revision `b`) ... FAILED +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/unknown_revision.rs ... FAILED tests/actual_tests_bless/unknown_revision2.rs ... FAILED tests/actual_tests_bless/wrong_diagnostic_code.rs ... FAILED @@ -842,11 +845,11 @@ full stdout: -FAILED TEST: tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `a`) +FAILED TEST: tests/actual_tests_bless/rustfix-fail-revisions.a.fixed (revision `a`) command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail-revisions.a.fixed" "--cfg=a" "--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" "--crate-name" "rustfix_fail_revisions" error: test got exit status: 1, but expected 0 - --> tests/actual_tests_bless/rustfix-fail-revisions.rs:2:9 + --> tests/actual_tests_bless/rustfix-fail-revisions.a.fixed:2:9 | 2 | #![deny(warnings)] | ^^^^^^^^ after rustfix is applied, all errors should be gone, but weren't @@ -873,11 +876,11 @@ full stdout: -FAILED TEST: tests/actual_tests_bless/rustfix-fail-revisions.rs (revision `b`) +FAILED TEST: tests/actual_tests_bless/rustfix-fail-revisions.b.fixed (revision `b`) command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail-revisions.b.fixed" "--cfg=b" "--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" "--crate-name" "rustfix_fail_revisions" error: test got exit status: 1, but expected 0 - --> tests/actual_tests_bless/rustfix-fail-revisions.rs:2:9 + --> tests/actual_tests_bless/rustfix-fail-revisions.b.fixed:2:9 | 2 | #![deny(warnings)] | ^^^^^^^^ after rustfix is applied, all errors should be gone, but weren't @@ -904,11 +907,11 @@ full stdout: -FAILED TEST: tests/actual_tests_bless/rustfix-fail.rs +FAILED TEST: tests/actual_tests_bless/rustfix-fail.fixed command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless/rustfix-fail.fixed" "--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" "--crate-name" "rustfix_fail" error: test got exit status: 1, but expected 0 - --> tests/actual_tests_bless/rustfix-fail.rs:1:9 + --> tests/actual_tests_bless/rustfix-fail.fixed:1:9 | 1 | #![deny(warnings)] | ^^^^^^^^ after rustfix is applied, all errors should be gone, but weren't @@ -1034,22 +1037,65 @@ FAILURES: tests/actual_tests_bless/revisioned_executable.rs (revision panic.run) tests/actual_tests_bless/revisioned_executable_panic.rs (revision run.run) tests/actual_tests_bless/revisions_bad.rs (revision bar) - tests/actual_tests_bless/rustfix-fail-revisions.rs (revision a) - tests/actual_tests_bless/rustfix-fail-revisions.rs (revision b) - tests/actual_tests_bless/rustfix-fail.rs + 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/unknown_revision.rs tests/actual_tests_bless/unknown_revision2.rs tests/actual_tests_bless/wrong_diagnostic_code.rs -test result: FAIL. 22 failed; 21 passed; 3 ignored; +test result: FAIL. 22 failed; 24 passed; 3 ignored; Building dependencies ... ok tests/actual_tests_bless_yolo/revisions_bad.rs (revision `foo`) ... ok tests/actual_tests_bless_yolo/revisions_bad.rs (revision `bar`) ... ok tests/actual_tests_bless_yolo/rustfix-maybe-incorrect.fixed ... ok tests/actual_tests_bless_yolo/rustfix-maybe-incorrect.rs ... ok +tests/actual_tests_bless_yolo/rustfix-multiple-fail.1.fixed ... ok +tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed ... FAILED +tests/actual_tests_bless_yolo/rustfix-multiple-fail.3.fixed ... ok +tests/actual_tests_bless_yolo/rustfix-multiple-fail.rs ... ok -test result: ok. 4 passed; +FAILED TEST: tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed +command: "rustc" "--error-format=json" "--out-dir" "$TMP "tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed" "--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" "--crate-name" "rustfix_multiple_fail" + +error: test got exit status: 1, but expected 0 + --> tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed:1:8 + | +1 | pub fn f(_: &i32) -> &i32 { + | ^ after rustfix is applied, all errors should be gone, but weren't + | + +full stderr: +error[E0308]: mismatched types + --> tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed:7:7 + | +7 | f(1); + | - ^ expected `&i32`, found integer + | | + | arguments to this function are incorrect + | +note: function defined here + --> tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed:1:8 + | +1 | pub fn f(_: &i32) -> &i32 { + | ^ ------- +help: consider borrowing here + | +7 | f(&1); + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. + +full stdout: + + +FAILURES: + tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed + +test result: FAIL. 1 failed; 7 passed; tests/actual_tests/bad_pattern.rs ... FAILED tests/actual_tests/executable.rs ... FAILED diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.1.fixed b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.1.fixed new file mode 100644 index 0000000..5732438 --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.1.fixed @@ -0,0 +1,8 @@ +pub fn f(_: i32) -> &'static i32 { + //~^ ERROR: missing lifetime + unimplemented!() +} + +fn main() { + f(1); +} diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed new file mode 100644 index 0000000..8f6b996 --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.2.fixed @@ -0,0 +1,8 @@ +pub fn f(_: &i32) -> &i32 { + //~^ ERROR: missing lifetime + unimplemented!() +} + +fn main() { + f(1); +} diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.3.fixed b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.3.fixed new file mode 100644 index 0000000..6c351ae --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.3.fixed @@ -0,0 +1,8 @@ +pub fn f(_: i32) -> i32 { + //~^ ERROR: missing lifetime + unimplemented!() +} + +fn main() { + f(1); +} diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.rs b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.rs new file mode 100644 index 0000000..c855e8e --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.rs @@ -0,0 +1,8 @@ +pub fn f(_: i32) -> &i32 { + //~^ ERROR: missing lifetime + unimplemented!() +} + +fn main() { + f(1); +} diff --git a/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.stderr b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.stderr new file mode 100644 index 0000000..6ad1823 --- /dev/null +++ b/tests/integrations/basic-fail/tests/actual_tests_bless_yolo/rustfix-multiple-fail.stderr @@ -0,0 +1,24 @@ +error[E0106]: missing lifetime specifier + --> tests/actual_tests_bless_yolo/rustfix-multiple-fail.rs:1:21 + | +1 | pub fn f(_: i32) -> &i32 { + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +1 | pub fn f(_: i32) -> &'static i32 { + | +++++++ +help: instead, you are more likely to want to change the argument to be borrowed... + | +1 | pub fn f(_: &i32) -> &i32 { + | + +help: ...or alternatively, you might want to return an owned value + | +1 - pub fn f(_: i32) -> &i32 { +1 + pub fn f(_: i32) -> i32 { + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/integrations/basic-fail/tests/ui_tests_bless.rs b/tests/integrations/basic-fail/tests/ui_tests_bless.rs index a13b284..7925df3 100644 --- a/tests/integrations/basic-fail/tests/ui_tests_bless.rs +++ b/tests/integrations/basic-fail/tests/ui_tests_bless.rs @@ -46,18 +46,13 @@ fn main() -> ui_test::color_eyre::Result<()> { config.stdout_filter("in ([0-9]m )?[0-9\\.]+s", ""); config.stderr_filter(r"[^ ]*/\.?cargo/registry/.*/", "$$CARGO_REGISTRY"); config.path_stderr_filter(&std::path::Path::new(path), "$DIR"); - let result = run_tests_generic( + let _ = run_tests_generic( vec![config], default_file_filter, default_per_file_config, // Avoid github actions, as these would end up showing up in `Cargo.stderr` status_emitter::Text::verbose(), ); - match (&result, rustfix) { - (Ok(_), RustfixMode::Everything) => {} - (Err(_), RustfixMode::MachineApplicable) => {} - _ => panic!("invalid mode/result combo: {rustfix:?}: {result:?}"), - } } Ok(()) } diff --git a/tests/integrations/basic/Cargo.stdout b/tests/integrations/basic/Cargo.stdout index 2684da5..55b82b2 100644 --- a/tests/integrations/basic/Cargo.stdout +++ b/tests/integrations/basic/Cargo.stdout @@ -33,13 +33,16 @@ tests/actual_tests/mac_span.rs ... ok tests/actual_tests/match_diagnostic_code.fixed ... ok tests/actual_tests/match_diagnostic_code.rs ... ok tests/actual_tests/no_rustfix.rs ... ok +tests/actual_tests/rustfix-multiple.1.fixed ... ok +tests/actual_tests/rustfix-multiple.2.fixed ... ok +tests/actual_tests/rustfix-multiple.rs ... ok tests/actual_tests/stdin.rs (revision `run`) ... ok tests/actual_tests/stdin.rs ... ok tests/actual_tests/unicode.rs ... ok tests/actual_tests/windows_paths.rs ... ok tests/actual_tests/subdir/aux_proc_macro.rs ... ok -test result: ok. 27 passed; +test result: ok. 30 passed; running 0 tests diff --git a/tests/integrations/basic/tests/actual_tests/rustfix-multiple.1.fixed b/tests/integrations/basic/tests/actual_tests/rustfix-multiple.1.fixed new file mode 100644 index 0000000..bef31b9 --- /dev/null +++ b/tests/integrations/basic/tests/actual_tests/rustfix-multiple.1.fixed @@ -0,0 +1,9 @@ +pub fn f() -> usize { + 1 +} + +pub fn g() { + f(); //~ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/integrations/basic/tests/actual_tests/rustfix-multiple.2.fixed b/tests/integrations/basic/tests/actual_tests/rustfix-multiple.2.fixed new file mode 100644 index 0000000..8eb690e --- /dev/null +++ b/tests/integrations/basic/tests/actual_tests/rustfix-multiple.2.fixed @@ -0,0 +1,9 @@ +pub fn f() -> usize { + 1 +} + +pub fn g() -> usize { + f() //~ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/integrations/basic/tests/actual_tests/rustfix-multiple.rs b/tests/integrations/basic/tests/actual_tests/rustfix-multiple.rs new file mode 100644 index 0000000..ad2aa8c --- /dev/null +++ b/tests/integrations/basic/tests/actual_tests/rustfix-multiple.rs @@ -0,0 +1,9 @@ +pub fn f() -> usize { + 1 +} + +pub fn g() { + f() //~ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/integrations/basic/tests/actual_tests/rustfix-multiple.stderr b/tests/integrations/basic/tests/actual_tests/rustfix-multiple.stderr new file mode 100644 index 0000000..7928b44 --- /dev/null +++ b/tests/integrations/basic/tests/actual_tests/rustfix-multiple.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> tests/actual_tests/rustfix-multiple.rs:6:5 + | +6 | f() + | ^^^ expected `()`, found `usize` + | +help: consider using a semicolon here + | +6 | f(); + | + +help: try adding a return type + | +5 | pub fn g() -> usize { + | ++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.