From f3f1749e9294bf87dd144a4181a95dbe00fea892 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 4 Mar 2026 14:26:10 -0600 Subject: [PATCH] fix(fix): Switch from ad-hoc to structured warnings --- src/cargo/util/diagnostic_server.rs | 107 +++++++++++++--------------- tests/testsuite/fix.rs | 29 +++++--- tests/testsuite/fix_n_times.rs | 95 ++++++------------------ 3 files changed, 92 insertions(+), 139 deletions(-) diff --git a/src/cargo/util/diagnostic_server.rs b/src/cargo/util/diagnostic_server.rs index ecb0f767e61..4f65af6a264 100644 --- a/src/cargo/util/diagnostic_server.rs +++ b/src/cargo/util/diagnostic_server.rs @@ -2,7 +2,6 @@ //! cross-platform way for the `cargo fix` command. use std::collections::HashSet; -use std::fmt::Write as _; use std::io::{BufReader, Read, Write}; use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream}; use std::path::PathBuf; @@ -10,6 +9,9 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::thread::{self, JoinHandle}; +use annotate_snippets::Group; +use annotate_snippets::Level; +use annotate_snippets::Origin; use anyhow::{Context as _, Error}; use cargo_util::ProcessBuilder; use serde::{Deserialize, Serialize}; @@ -128,15 +130,15 @@ impl<'a> DiagnosticPrinter<'a> { Message::ReplaceFailed { file, message } => { let issue_link = get_bug_report_url(self.workspace_wrapper); - let mut msg = format!("error applying suggestions to `{file}`\n"); - writeln!(&mut msg)?; - writeln!(&mut msg, "The full error message was:")?; - writeln!(&mut msg)?; - writeln!(&mut msg, "> {message}")?; - writeln!(&mut msg)?; - writeln!(&mut msg, "{}", gen_please_report_this_bug_text(issue_link))?; - writeln!(&mut msg, "{}", gen_suggest_broken_code())?; - self.gctx.shell().warn(&msg)?; + let report = &[ + Level::ERROR + .secondary_title("error applying suggestions") + .element(Origin::path(file)) + .element(Level::ERROR.with_name("cause").message(message)), + gen_please_report_this_bug_group(issue_link), + gen_suggest_broken_code_group(), + ]; + self.gctx.shell().print_report(report, false)?; Ok(()) } Message::FixFailed { @@ -152,42 +154,34 @@ impl<'a> DiagnosticPrinter<'a> { }; let issue_link = get_bug_report_url(self.workspace_wrapper); - let mut msg = - format!("failed to automatically apply fixes suggested by rustc{to_crate}\n"); - if !files.is_empty() { - writeln!(&mut msg)?; - writeln!( - &mut msg, - "after fixes were automatically applied the compiler \ - reported errors within these files:" - )?; - writeln!(&mut msg)?; - for file in files { - writeln!(&mut msg, " * {file}")?; - } - writeln!(&mut msg)?; - } - write!( - &mut msg, - "{}\n", - gen_please_report_this_bug_text(issue_link) - )?; - write!(&mut msg, "{}\n\n", gen_suggest_broken_code())?; - if !errors.is_empty() { - writeln!(&mut msg, "The following errors were reported:")?; - for error in errors { - write!(&mut msg, "{error}")?; - if !error.ends_with('\n') { - writeln!(&mut msg)?; - } - } - } - if let Some(exit) = abnormal_exit { - writeln!(&mut msg, "rustc exited abnormally: {exit}")?; - } - writeln!(&mut msg, "Original diagnostics will follow.")?; + let cause_message = if !errors.is_empty() { + Some(errors.join("\n").trim().to_owned()) + } else { + 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:"), + ), + ]; - self.gctx.shell().warn(&msg)?; + self.gctx.shell().print_report(report, false)?; Ok(()) } Message::EditionAlreadyEnabled { message, edition } => { @@ -223,22 +217,17 @@ https://doc.rust-lang.org/edition-guide/editions/transitioning-an-existing-proje } } -fn gen_please_report_this_bug_text(url: &str) -> String { - format!( - "This likely indicates a bug in either rustc or cargo itself,\n\ - and we would appreciate a bug report! You're likely to see\n\ - a number of compiler warnings after this message which cargo\n\ - attempted to fix but failed. If you could open an issue at\n\ - {url}\n\ - quoting the full output of this command we'd be very appreciative!\ - ", - ) +fn gen_please_report_this_bug_group(url: &str) -> Group<'static> { + Group::with_title(Level::HELP.secondary_title(format!( + "to report this as a bug, open an issue at {url}, quoting the full output of this command" + ))) } -fn gen_suggest_broken_code() -> &'static str { - "Note that you may be able to make some more progress in the near-term\n\ - fixing code with the `--broken-code` flag\ - " +fn gen_suggest_broken_code_group() -> Group<'static> { + Group::with_title( + Level::HELP + .secondary_title("to possibly apply more fixes, pass in the `--broken-code` flag"), + ) } fn get_bug_report_url(rustc_workspace_wrapper: &Option) -> &str { diff --git a/tests/testsuite/fix.rs b/tests/testsuite/fix.rs index 1fafbbfa163..cc157b198e9 100644 --- a/tests/testsuite/fix.rs +++ b/tests/testsuite/fix.rs @@ -1429,9 +1429,17 @@ fn fix_to_broken_code() { .cwd("bar") .env("RUSTC", p.root().join("foo/target/debug/foo")) .with_stderr_data(str![[r#" +[COMPILING] bar v0.1.0 ([ROOT]/foo/bar) +[ERROR] errors present after applying fixes to crate `bar` + | + = 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 +[NOTE] original diagnostics will follow: ... -[WARNING] failed to automatically apply fixes suggested by rustc to crate `bar` -... + "#]]) .run(); @@ -1772,13 +1780,18 @@ fn abnormal_exit() { ) // "signal: 6, SIGABRT: process abort signal" on some platforms .with_stderr_data(str![[r#" +[LOCKING] 1 package to latest compatible version +[COMPILING] pm v0.1.0 ([ROOT]/foo/pm) +[CHECKING] foo v0.1.0 ([ROOT]/foo) +[ERROR] errors present after applying fixes to crate `foo` + | + = cause: I'm not a diagnostic. + = cause: rustc exited abnormally: [..] +[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 +[NOTE] original diagnostics will follow: ... -[WARNING] failed to automatically apply fixes suggested by rustc to crate `foo` -... -I'm not a diagnostic. -rustc exited abnormally: [..] -Original diagnostics will follow. -... + "#]]) .run(); } diff --git a/tests/testsuite/fix_n_times.rs b/tests/testsuite/fix_n_times.rs index 606cc80870c..6ba05a04bd9 100644 --- a/tests/testsuite/fix_n_times.rs +++ b/tests/testsuite/fix_n_times.rs @@ -327,21 +327,11 @@ fn fix_overlapping_max() { |_execs| {}, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) -[WARNING] error applying suggestions to `src/lib.rs` - -The full error message was: - -> cannot replace slice of data that was already replaced - -This likely indicates a bug in either rustc or cargo itself, -and we would appreciate a bug report! You're likely to see -a number of compiler warnings after this message which cargo -attempted to fix but failed. If you could open an issue at -https://github.com/rust-lang/rust/issues -quoting the full output of this command we'd be very appreciative! -Note that you may be able to make some more progress in the near-term -fixing code with the `--broken-code` flag - +[ERROR] error applying suggestions + --> src/lib.rs + = cause: cannot replace slice of data that was already replaced +[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 [FIXED] src/lib.rs (4 fixes) rustc fix shim comment 5 rustc fix shim comment 6 @@ -362,25 +352,12 @@ fn fix_verification_failed() { |_execs| {}, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) -[WARNING] failed to automatically apply fixes suggested by rustc to crate `foo` - -after fixes were automatically applied the compiler reported errors within these files: - - * src/lib.rs - -This likely indicates a bug in either rustc or cargo itself, -and we would appreciate a bug report! You're likely to see -a number of compiler warnings after this message which cargo -attempted to fix but failed. If you could open an issue at -https://github.com/rust-lang/rust/issues -quoting the full output of this command we'd be very appreciative! -Note that you may be able to make some more progress in the near-term -fixing code with the `--broken-code` flag - -The following errors were reported: -rustc fix shim error count=2 -Original diagnostics will follow. - +[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 +[NOTE] original diagnostics will follow: rustc fix shim comment 1 [WARNING] `foo` (lib) generated 1 warning (run `cargo fix --lib -p foo` to apply 1 suggestion) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s @@ -402,25 +379,12 @@ fn fix_verification_failed_clippy() { }, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) -[WARNING] failed to automatically apply fixes suggested by rustc to crate `foo` - -after fixes were automatically applied the compiler reported errors within these files: - - * src/lib.rs - -This likely indicates a bug in either rustc or cargo itself, -and we would appreciate a bug report! You're likely to see -a number of compiler warnings after this message which cargo -attempted to fix but failed. If you could open an issue at -https://github.com/rust-lang/rust-clippy/issues -quoting the full output of this command we'd be very appreciative! -Note that you may be able to make some more progress in the near-term -fixing code with the `--broken-code` flag - -The following errors were reported: -rustc fix shim error count=2 -Original diagnostics will follow. - +[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-clippy/issues, quoting the full output of this command +[HELP] to possibly apply more fixes, pass in the `--broken-code` flag +[NOTE] original diagnostics will follow: rustc fix shim comment 1 [WARNING] `foo` (lib) generated 1 warning (run `cargo clippy --fix --lib -p foo` to apply 1 suggestion) [FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s @@ -493,25 +457,12 @@ fn broken_code_one_suggestion() { }, str![[r#" [CHECKING] foo v0.0.1 ([ROOT]/foo) -[WARNING] failed to automatically apply fixes suggested by rustc to crate `foo` - -after fixes were automatically applied the compiler reported errors within these files: - - * src/lib.rs - -This likely indicates a bug in either rustc or cargo itself, -and we would appreciate a bug report! You're likely to see -a number of compiler warnings after this message which cargo -attempted to fix but failed. If you could open an issue at -https://github.com/rust-lang/rust/issues -quoting the full output of this command we'd be very appreciative! -Note that you may be able to make some more progress in the near-term -fixing code with the `--broken-code` flag - -The following errors were reported: -rustc fix shim error count=2 -Original diagnostics will follow. - +[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 +[NOTE] original diagnostics will follow: rustc fix shim comment 1 rustc fix shim error count=2 [WARNING] `foo` (lib) generated 1 warning