Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/bin/cargo/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,14 @@ fn config_configure(
if let Some(values) = args.get_many::<String>("config") {
config_args.extend(values.cloned());
}
let summary_override = if subcommand_args.flag("summary") {
Some(true)
} else if subcommand_args.flag("no-summary") {
Some(false)
} else {
None
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest avoiding adding a new flag at first place. This is a one way door decision and cannot be reverted once stabilized. We could figure it out in follow-up PRs and discussions.


config.configure(
verbose,
quiet,
Expand All @@ -349,6 +357,7 @@ fn config_configure(
locked,
offline,
arg_target_dir,
summary_override,
&unstable_flags,
&config_args,
)?;
Expand Down
2 changes: 2 additions & 0 deletions src/bin/cargo/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ pub fn cli() -> Command {
.arg_unit_graph()
.arg_future_incompat_report()
.arg_timings()
.arg_show_summary()
.arg_hide_summary()
.after_help("Run `cargo help build` for more detailed information.\n")
}

Expand Down
2 changes: 2 additions & 0 deletions src/bin/cargo/commands/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub fn cli() -> Command {
.arg_unit_graph()
.arg_future_incompat_report()
.arg_timings()
.arg_show_summary()
.arg_hide_summary()
.after_help("Run `cargo help check` for more detailed information.\n")
}

Expand Down
2 changes: 2 additions & 0 deletions src/bin/cargo/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub fn cli() -> Command {
.arg_unit_graph()
.arg_ignore_rust_version()
.arg_timings()
.arg_show_summary()
.arg_hide_summary()
.after_help("Run `cargo help run` for more detailed information.\n")
}

Expand Down
49 changes: 48 additions & 1 deletion src/cargo/core/compiler/job_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ struct DrainState<'cfg> {
diag_dedupe: DiagDedupe<'cfg>,
/// Count of warnings, used to print a summary after the job succeeds
warning_count: HashMap<JobId, WarningCount>,
diagnostic_codes: HashMap<JobId, HashMap<String, usize>>,
active: HashMap<JobId, Unit>,
compiled: HashSet<PackageId>,
documented: HashSet<PackageId>,
Expand Down Expand Up @@ -202,6 +203,9 @@ impl WarningCount {
}
}

// If the total number of diagnostics is at least this many, then output a summary.
const DIAGNOSTIC_SUMMARY_THRESHOLD: usize = 10;

/// Used to keep track of how many fixable warnings there are
/// and if fixable warnings are allowed
#[derive(Default)]
Expand Down Expand Up @@ -356,6 +360,7 @@ enum Message {
level: String,
diag: String,
fixable: bool,
code: Option<String>,
},
// This handles duplicate output that is suppressed, for showing
// only a count of duplicate messages instead
Expand Down Expand Up @@ -420,7 +425,13 @@ impl<'a, 'cfg> JobState<'a, 'cfg> {
}

/// See [`Message::Diagnostic`] and [`Message::WarningCount`].
pub fn emit_diag(&self, level: String, diag: String, fixable: bool) -> CargoResult<()> {
pub fn emit_diag(
&self,
level: String,
diag: String,
fixable: bool,
code: Option<String>,
) -> CargoResult<()> {
if let Some(dedupe) = self.output {
let emitted = dedupe.emit_diag(&diag)?;
if level == "warning" {
Expand All @@ -436,6 +447,7 @@ impl<'a, 'cfg> JobState<'a, 'cfg> {
level,
diag,
fixable,
code,
});
}
Ok(())
Expand Down Expand Up @@ -586,6 +598,7 @@ impl<'cfg> JobQueue<'cfg> {
messages: Arc::new(Queue::new(100)),
diag_dedupe: DiagDedupe::new(cx.bcx.config),
warning_count: HashMap::new(),
diagnostic_codes: HashMap::new(),
active: HashMap::new(),
compiled: HashSet::new(),
documented: HashSet::new(),
Expand Down Expand Up @@ -755,7 +768,11 @@ impl<'cfg> DrainState<'cfg> {
level,
diag,
fixable,
code,
} => {
if let Some(code) = code {
self.bump_diagnostic_count(id, code);
}
let emitted = self.diag_dedupe.emit_diag(&diag)?;
if level == "warning" {
self.bump_warning_count(id, emitted, fixable);
Expand Down Expand Up @@ -1247,6 +1264,12 @@ impl<'cfg> DrainState<'cfg> {
}
}

fn bump_diagnostic_count(&mut self, id: JobId, code: String) {
let code_counts = self.diagnostic_codes.entry(id).or_default();
let total = code_counts.entry(code).or_default();
*total += 1;
}

/// Displays a final report of the warnings emitted by a particular job.
fn report_warning_count(
&mut self,
Expand Down Expand Up @@ -1320,6 +1343,30 @@ impl<'cfg> DrainState<'cfg> {
}
}
}

let mut diag_stats: Vec<(String, usize)> = self
.diagnostic_codes
.remove(&id)
.unwrap_or_default()
.into_iter()
.collect();
let total_diag_count: usize = diag_stats.iter().map(|(_, count)| count).sum();

let print_summary = config
.summary_override
.unwrap_or(total_diag_count >= DIAGNOSTIC_SUMMARY_THRESHOLD);
if print_summary {
// we sort the each diagnostic count by count and name. We will primarily sort descending by count, and for
// entries with the same count we shall sort by alphabetic order by the lint name.
diag_stats
.sort_by(|(name1, count1), (name2, count2)| (count2, name1).cmp(&(count1, name2)));
message.push_str("\n\n");
message.push_str("Summary of diagnostics:\n");
for (name, count) in diag_stats {
message.push_str(format!("{name}: {count}\n").as_str());
}
}

// Errors are ignored here because it is tricky to handle them
// correctly, and they aren't important.
drop(config.shell().warn(message));
Expand Down
12 changes: 11 additions & 1 deletion src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1502,12 +1502,17 @@ fn on_stderr_line_inner(
render_diagnostics: true,
..
} => {
#[derive(serde::Deserialize)]
struct DiagnosticCode {
code: String,
}
#[derive(serde::Deserialize)]
struct CompilerMessage {
rendered: String,
message: String,
level: String,
children: Vec<PartialDiagnostic>,
code: Option<DiagnosticCode>,
}

// A partial rustfix::diagnostics::Diagnostic. We deserialize only a
Expand Down Expand Up @@ -1563,7 +1568,12 @@ fn on_stderr_line_inner(
})
.any(|b| b);
count_diagnostic(&msg.level, options);
state.emit_diag(msg.level, rendered, machine_applicable)?;
state.emit_diag(
msg.level,
rendered,
machine_applicable,
msg.code.map(|code| code.code),
)?;
}
return Ok(true);
}
Expand Down
8 changes: 8 additions & 0 deletions src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,14 @@ pub trait CommandExt: Sized {
.require_equals(true),
)
}

fn arg_show_summary(self) -> Self {
self._arg(flag("summary", "Show diagnostic summary"))
}

fn arg_hide_summary(self) -> Self {
self._arg(flag("no-summary", "Suppress diagnostic summary"))
}
}

impl CommandExt for Command {
Expand Down
6 changes: 6 additions & 0 deletions src/cargo/util/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,9 @@ pub struct Config {
pub nightly_features_allowed: bool,
/// WorkspaceRootConfigs that have been found
pub ws_roots: RefCell<HashMap<PathBuf, WorkspaceRootConfig>>,
/// By default, a summary is shown if `cargo clippy` gives many warnings.
/// This field overrides default behavior if the option is a Some variant.
pub summary_override: Option<bool>,
}

impl Config {
Expand Down Expand Up @@ -331,6 +334,7 @@ impl Config {
env_config: LazyCell::new(),
nightly_features_allowed: matches!(&*features::channel(), "nightly" | "dev"),
ws_roots: RefCell::new(HashMap::new()),
summary_override: None,
}
}

Expand Down Expand Up @@ -957,6 +961,7 @@ impl Config {
locked: bool,
offline: bool,
target_dir: &Option<PathBuf>,
summary_override: Option<bool>,
unstable_flags: &[String],
cli_config: &[String],
) -> CargoResult<()> {
Expand Down Expand Up @@ -1024,6 +1029,7 @@ impl Config {
.and_then(|n| n.offline)
.unwrap_or(false);
self.target_dir = cli_target_dir;
self.summary_override = summary_override;

self.load_unstable_flags_from_config()?;

Expand Down
1 change: 1 addition & 0 deletions tests/testsuite/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ impl ConfigBuilder {
false,
false,
&None,
None,
&self.unstable,
&self.config_args,
)?;
Expand Down