diff --git a/lintcheck/src/json.rs b/lintcheck/src/json.rs index 410f19f27b8..74f36f000bd 100644 --- a/lintcheck/src/json.rs +++ b/lintcheck/src/json.rs @@ -9,6 +9,7 @@ #[derive(Deserialize, Serialize)] struct LintJson { lint: String, + krate: String, file_name: String, byte_pos: (u32, u32), file_link: String, @@ -19,6 +20,10 @@ impl LintJson { fn key(&self) -> impl Ord + '_ { (self.file_name.as_str(), self.byte_pos, self.lint.as_str()) } + + fn info_text(&self, action: &str) -> String { + format!("{action} `{}` in `{}` at {}", self.lint, self.krate, self.file_link) + } } /// Creates the log file output for [`crate::config::OutputFormat::Json`] @@ -30,6 +35,7 @@ pub(crate) fn output(clippy_warnings: Vec) -> String { LintJson { file_name: span.file_name.clone(), byte_pos: (span.byte_start, span.byte_end), + krate: warning.krate, file_link: warning.url, lint: warning.lint, rendered: warning.diag.rendered.unwrap(), @@ -51,12 +57,16 @@ fn print_warnings(title: &str, warnings: &[LintJson]) { return; } - println!("### {title}"); + //We have to use HTML here to be able to manually add an id. + println!(r#"

{title}

"#); + println!(); for warning in warnings { - println!("{title} `{}` at {}", warning.lint, warning.file_link); + println!("{}", warning.info_text(title)); + println!(); println!("```"); - print!("{}", warning.rendered); + println!("{}", warning.rendered.trim_end()); println!("```"); + println!(); } } @@ -65,11 +75,14 @@ fn print_changed_diff(changed: &[(LintJson, LintJson)]) { return; } - println!("### Changed"); + //We have to use HTML here to be able to manually add an id. + println!(r#"

Changed

"#); + println!(); for (old, new) in changed { - println!("Changed `{}` at {}", new.lint, new.file_link); + println!("{}", new.info_text("Changed")); + println!(); println!("```diff"); - for change in diff::lines(&old.rendered, &new.rendered) { + for change in diff::lines(old.rendered.trim_end(), new.rendered.trim_end()) { use diff::Result::{Both, Left, Right}; match change { @@ -109,13 +122,30 @@ pub(crate) fn diff(old_path: &Path, new_path: &Path) { } print!( - "{} added, {} removed, {} changed\n\n", - added.len(), - removed.len(), - changed.len() + r##"{}, {}, {}"##, + count_string("added", added.len()), + count_string("removed", removed.len()), + count_string("changed", changed.len()), ); + println!(); + println!(); print_warnings("Added", &added); print_warnings("Removed", &removed); print_changed_diff(&changed); } + +/// This generates the `x added` string for the start of the job summery. +/// It linkifies them if possible to jump to the respective heading. +fn count_string(label: &str, count: usize) -> String { + // Headlines are only added, if anything will be displayed under the headline. + // We therefore only want to add links to them if they exist + if count == 0 { + format!("0 {label}") + } else { + // GitHub's job summaries don't add HTML ids to headings. That's why we + // manually have to add them. GitHub prefixes these manual ids with + // `user-content-` and that's how we end up with these awesome links :D + format!("[{count} {label}](#user-content-{label})") + } +} diff --git a/lintcheck/src/main.rs b/lintcheck/src/main.rs index 28b05d2460d..db1ecb9e663 100644 --- a/lintcheck/src/main.rs +++ b/lintcheck/src/main.rs @@ -189,6 +189,7 @@ fn run_clippy_lints( Ok(Message::CompilerMessage(message)) => ClippyWarning::new( normalize_diag(message.message, shared_target_dir.to_str().unwrap()), &self.base_url, + &self.name, ), _ => None, }) diff --git a/lintcheck/src/output.rs b/lintcheck/src/output.rs index f785347de80..15378630695 100644 --- a/lintcheck/src/output.rs +++ b/lintcheck/src/output.rs @@ -53,12 +53,13 @@ pub fn from_stderr_and_status(crate_name: &str, status: ExitStatus, stderr: &str pub struct ClippyWarning { pub lint: String, pub diag: Diagnostic, + pub krate: String, /// The URL that points to the file and line of the lint emission pub url: String, } impl ClippyWarning { - pub fn new(mut diag: Diagnostic, base_url: &str) -> Option { + pub fn new(mut diag: Diagnostic, base_url: &str, krate: &str) -> Option { let lint = diag.code.clone()?.code; if !(lint.contains("clippy") || diag.message.contains("clippy")) || diag.message.contains("could not read cargo metadata") @@ -90,7 +91,12 @@ pub fn new(mut diag: Diagnostic, base_url: &str) -> Option { file.clone() }; - Some(Self { lint, diag, url }) + Some(Self { + lint, + diag, + url, + krate: krate.to_string(), + }) } pub fn span(&self) -> &DiagnosticSpan { diff --git a/lintcheck/src/recursive.rs b/lintcheck/src/recursive.rs index 6817d917b93..6a662970ae8 100644 --- a/lintcheck/src/recursive.rs +++ b/lintcheck/src/recursive.rs @@ -72,7 +72,7 @@ fn process_stream( let messages = stderr .lines() .filter_map(|json_msg| serde_json::from_str::(json_msg).ok()) - .filter_map(|diag| ClippyWarning::new(diag, &base_url)); + .filter_map(|diag| ClippyWarning::new(diag, &base_url, &driver_info.package_name)); for message in messages { sender.send(message).unwrap();