diff --git a/crates/cargo-util-terminal/src/shell.rs b/crates/cargo-util-terminal/src/shell.rs index e39d231e7dd..a6bdd35d05e 100644 --- a/crates/cargo-util-terminal/src/shell.rs +++ b/crates/cargo-util-terminal/src/shell.rs @@ -233,6 +233,14 @@ impl Shell { self.print_report(report, false) } + /// Prints a cyan 'help' message. + pub fn help(&mut self, message: T) -> CargoResult<()> { + let report = &[annotate_snippets::Group::with_title( + annotate_snippets::Level::HELP.secondary_title(message.to_string()), + )]; + self.print_report(report, false) + } + /// Updates the verbosity of the shell. pub fn set_verbosity(&mut self, verbosity: Verbosity) { self.verbosity = verbosity; diff --git a/src/cargo/ops/fix/mod.rs b/src/cargo/ops/fix/mod.rs index e7632e43e76..2aa814f08c6 100644 --- a/src/cargo/ops/fix/mod.rs +++ b/src/cargo/ops/fix/mod.rs @@ -791,10 +791,26 @@ pub fn fix_exec_rustc(gctx: &GlobalContext, lock_addr: &str) -> CargoResult<()> // If there were any fixes, let the user know that there was a failure // attempting to apply them, and to ask for a bug report. - // - // FIXME: The error message here is not correct with --broken-code. - // https://github.com/rust-lang/cargo/issues/10955 if fixes.files.is_empty() { + if !fixes.last_output.status.success() { + if allow_broken_code { + gctx.shell() + .warn("no fixes were suggested because the code is already broken")?; + gctx.shell().note( + "cargo fix requires code that compiles successfully to apply automatic fixes", + )?; + gctx.shell() + .note("the broken code was saved due to `--broken-code`")?; + } else { + gctx.shell() + .warn("no fixes were suggested because the code is already broken")?; + gctx.shell().note( + "cargo fix requires code that compiles successfully to apply automatic fixes", + )?; + gctx.shell() + .help("use `--broken-code` to save partial progress")?; + } + } // No fixes were available. Display whatever errors happened. emit_output(&fixes.last_output)?; exit_with(fixes.last_output.status); @@ -814,6 +830,7 @@ pub fn fix_exec_rustc(gctx: &GlobalContext, lock_addr: &str) -> CargoResult<()> krate, &fixes.last_output.stderr, fixes.last_output.status, + allow_broken_code, )?; // Display the diagnostics that appeared at the start, before the // fixes failed. This can help with diagnosing which suggestions @@ -1171,6 +1188,7 @@ fn log_failed_fix( krate: Option, stderr: &[u8], status: ExitStatus, + allow_broken_code: bool, ) -> CargoResult<()> { let stderr = str::from_utf8(stderr).context("failed to parse rustc stderr as utf-8")?; @@ -1205,6 +1223,7 @@ fn log_failed_fix( krate, errors, abnormal_exit, + allow_broken_code, } .post(gctx)?; diff --git a/src/cargo/util/diagnostic_server.rs b/src/cargo/util/diagnostic_server.rs index 84e3cc45608..4d63ece9bca 100644 --- a/src/cargo/util/diagnostic_server.rs +++ b/src/cargo/util/diagnostic_server.rs @@ -43,6 +43,7 @@ pub enum Message { krate: Option, errors: Vec, abnormal_exit: Option, + allow_broken_code: bool, }, ReplaceFailed { file: String, @@ -146,6 +147,7 @@ impl<'a> DiagnosticPrinter<'a> { krate, errors, abnormal_exit, + allow_broken_code, } => { let to_crate = if let Some(ref krate) = *krate { format!(" to crate `{krate}`",) @@ -160,28 +162,36 @@ impl<'a> DiagnosticPrinter<'a> { None }; - let report = &[ - Level::ERROR - .secondary_title(format!("errors present after applying fixes{to_crate}")) - .elements(files.iter().map(|f| Origin::path(f))) - .elements( - cause_message - .into_iter() - .map(|err| Level::ERROR.with_name("cause").message(err)), - ) - .elements(abnormal_exit.iter().map(|exit| { - Level::ERROR - .with_name("cause") - .message(format!("rustc exited abnormally: {exit}")) - })), - gen_please_report_this_bug_group(issue_link), - gen_suggest_broken_code_group(), - Group::with_title( - Level::NOTE.secondary_title("original diagnostics will follow:"), - ), - ]; + let report = &[Level::ERROR + .secondary_title(format!("errors present after applying fixes{to_crate}")) + .elements(files.iter().map(|f| Origin::path(f))) + .elements( + cause_message + .into_iter() + .map(|err| Level::ERROR.with_name("cause").message(err)), + ) + .elements(abnormal_exit.iter().map(|exit| { + Level::ERROR + .with_name("cause") + .message(format!("rustc exited abnormally: {exit}")) + }))]; + + let mut report = report.to_vec(); + + if *allow_broken_code { + report.push(Group::with_title(Level::WARNING.secondary_title( + "fixes were applied but the code still does not compile; partially-fixed code was saved due to `--broken-code`" + ))); + } else { + report.push(gen_please_report_this_bug_group(issue_link)); + report.push(gen_suggest_broken_code_group()); + } - self.gctx.shell().print_report(report, false)?; + report.push(Group::with_title( + Level::NOTE.secondary_title("original diagnostics will follow:"), + )); + + self.gctx.shell().print_report(&report, false)?; Ok(()) } Message::EditionAlreadyEnabled { message, edition } => { diff --git a/tests/testsuite/fix.rs b/tests/testsuite/fix.rs index cc157b198e9..c32eab8f7ca 100644 --- a/tests/testsuite/fix.rs +++ b/tests/testsuite/fix.rs @@ -1435,8 +1435,7 @@ fn fix_to_broken_code() { = cause: thread 'main' ([..]) panicked at src/main.rs:23:29: explicit panic [NOTE] run with `RUST_BACKTRACE=1` environment variable to display a backtrace -[HELP] to report this as a bug, open an issue at https://github.com/rust-lang/rust/issues, quoting the full output of this command -[HELP] to possibly apply more fixes, pass in the `--broken-code` flag +[WARNING] fixes were applied but the code still does not compile; partially-fixed code was saved due to `--broken-code` [NOTE] original diagnostics will follow: ... @@ -2381,6 +2380,9 @@ fn fix_in_rust_src() { .with_status(101) .with_stderr_data(str![[r#" [CHECKING] foo v0.0.0 ([ROOT]/foo) +[WARNING] no fixes were suggested because the code is already broken +[NOTE] cargo fix requires code that compiles successfully to apply automatic fixes +[NOTE] the broken code was saved due to `--broken-code` error[E0308]: mismatched types --> lib.rs:5:9 | diff --git a/tests/testsuite/fix_n_times.rs b/tests/testsuite/fix_n_times.rs index dfbb611c235..98ccf5a736e 100644 --- a/tests/testsuite/fix_n_times.rs +++ b/tests/testsuite/fix_n_times.rs @@ -532,6 +532,9 @@ fn starts_with_error() { }, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) +[WARNING] no fixes were suggested because the code is already broken +[NOTE] cargo fix requires code that compiles successfully to apply automatic fixes +[HELP] use `--broken-code` to save partial progress rustc fix shim error count=1 [ERROR] could not compile `foo` (lib) due to 1 previous error @@ -550,6 +553,9 @@ fn broken_code_no_suggestions() { }, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) +[WARNING] no fixes were suggested because the code is already broken +[NOTE] cargo fix requires code that compiles successfully to apply automatic fixes +[NOTE] the broken code was saved due to `--broken-code` rustc fix shim error count=1 [ERROR] could not compile `foo` (lib) due to 1 previous error @@ -571,8 +577,7 @@ fn broken_code_one_suggestion() { [ERROR] errors present after applying fixes to crate `foo` --> src/lib.rs = cause: rustc fix shim error count=2 -[HELP] to report this as a bug, open an issue at https://github.com/rust-lang/rust/issues, quoting the full output of this command -[HELP] to possibly apply more fixes, pass in the `--broken-code` flag +[WARNING] fixes were applied but the code still does not compile; partially-fixed code was saved due to `--broken-code` [NOTE] original diagnostics will follow: rustc fix shim comment 1 rustc fix shim error count=2