Skip to content

Commit dd69ce1

Browse files
committed
add a note that some warnings can be auto-fixed
1 parent 3ff0443 commit dd69ce1

File tree

5 files changed

+405
-13
lines changed

5 files changed

+405
-13
lines changed

src/cargo/core/compiler/job_queue.rs

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,11 @@ struct DrainState<'cfg> {
131131
diag_dedupe: DiagDedupe<'cfg>,
132132
/// Count of warnings, used to print a summary after the job succeeds.
133133
///
134-
/// First value is the total number of warnings, and the second value is
134+
/// First value is the total number of warnings, the second value is
135135
/// the number that were suppressed because they were duplicates of a
136-
/// previous warning.
137-
warning_count: HashMap<JobId, (usize, usize)>,
136+
/// previous warning, and the third value is for the number of fixable
137+
/// warnings (set to -1 if there are any errors).
138+
warning_count: HashMap<JobId, (usize, usize, isize)>,
138139
active: HashMap<JobId, Unit>,
139140
compiled: HashSet<PackageId>,
140141
documented: HashSet<PackageId>,
@@ -311,10 +312,12 @@ enum Message {
311312
id: JobId,
312313
level: String,
313314
diag: String,
315+
fixable: bool,
314316
},
315317
WarningCount {
316318
id: JobId,
317319
emitted: bool,
320+
fixable: bool,
318321
},
319322
FixDiagnostic(diagnostic_server::Message),
320323
Token(io::Result<Acquired>),
@@ -363,20 +366,22 @@ impl<'a, 'cfg> JobState<'a, 'cfg> {
363366
Ok(())
364367
}
365368

366-
pub fn emit_diag(&self, level: String, diag: String) -> CargoResult<()> {
369+
pub fn emit_diag(&self, level: String, diag: String, fixable: bool) -> CargoResult<()> {
367370
if let Some(dedupe) = self.output {
368371
let emitted = dedupe.emit_diag(&diag)?;
369372
if level == "warning" {
370373
self.messages.push(Message::WarningCount {
371374
id: self.id,
372375
emitted,
376+
fixable,
373377
});
374378
}
375379
} else {
376380
self.messages.push_bounded(Message::Diagnostic {
377381
id: self.id,
378382
level,
379383
diag,
384+
fixable,
380385
});
381386
}
382387
Ok(())
@@ -679,14 +684,31 @@ impl<'cfg> DrainState<'cfg> {
679684
shell.print_ansi_stderr(err.as_bytes())?;
680685
shell.err().write_all(b"\n")?;
681686
}
682-
Message::Diagnostic { id, level, diag } => {
687+
Message::Diagnostic {
688+
id,
689+
level,
690+
diag,
691+
fixable,
692+
} => {
683693
let emitted = self.diag_dedupe.emit_diag(&diag)?;
684694
if level == "warning" {
685-
self.bump_warning_count(id, emitted);
695+
self.bump_warning_count(id, emitted, fixable);
696+
}
697+
if level == "error" {
698+
// If there is an error set fixable count to -1 so the `cargo fix`
699+
// message does not show
700+
let cnts = self.warning_count.entry(id).or_default();
701+
if fixable {
702+
cnts.2 = -1;
703+
}
686704
}
687705
}
688-
Message::WarningCount { id, emitted } => {
689-
self.bump_warning_count(id, emitted);
706+
Message::WarningCount {
707+
id,
708+
emitted,
709+
fixable,
710+
} => {
711+
self.bump_warning_count(id, emitted, fixable);
690712
}
691713
Message::FixDiagnostic(msg) => {
692714
self.print.print(&msg)?;
@@ -1127,18 +1149,34 @@ impl<'cfg> DrainState<'cfg> {
11271149
Ok(())
11281150
}
11291151

1130-
fn bump_warning_count(&mut self, id: JobId, emitted: bool) {
1152+
fn bump_warning_count(&mut self, id: JobId, emitted: bool, fixable: bool) {
11311153
let cnts = self.warning_count.entry(id).or_default();
11321154
cnts.0 += 1;
11331155
if !emitted {
11341156
cnts.1 += 1;
1157+
// Don't add to fixable if it's already been emitted
1158+
} else if fixable {
1159+
// Do not add anything to the fixable warning count if
1160+
// is `-1` since that indicates there was an error while
1161+
// building this `Unit`
1162+
if cnts.2 >= 0 {
1163+
cnts.2 += 1;
1164+
}
11351165
}
11361166
}
11371167

11381168
/// Displays a final report of the warnings emitted by a particular job.
11391169
fn report_warning_count(&mut self, config: &Config, id: JobId) {
11401170
let count = match self.warning_count.remove(&id) {
1141-
Some(count) => count,
1171+
Some(count) => {
1172+
// An error could add an entry for a `Unit`
1173+
// with 0 warnings but with count.2 = -1
1174+
if count.0 > 0 {
1175+
count
1176+
} else {
1177+
return;
1178+
}
1179+
}
11421180
None => return,
11431181
};
11441182
let unit = &self.active[&id];
@@ -1160,6 +1198,41 @@ impl<'cfg> DrainState<'cfg> {
11601198
1 => message.push_str(" (1 duplicate)"),
11611199
n => drop(write!(message, " ({} duplicates)", n)),
11621200
}
1201+
// Only show the `cargo fix` message if its a local `Unit`
1202+
if unit.is_local() && config.nightly_features_allowed {
1203+
match count.2 {
1204+
// Do not show this if there are any errors (-1) or no fixable warnings
1205+
-1 | 0 => {}
1206+
n => {
1207+
// `cargo fix` doesnt have an option for custom builds
1208+
if !unit.target.is_custom_build() {
1209+
let mut command = {
1210+
let named = unit.target.description_named();
1211+
// if its a lib we need to add the package to fix
1212+
if named == "lib" {
1213+
format!("{} -p {}", named, unit.pkg.name())
1214+
} else {
1215+
named
1216+
}
1217+
};
1218+
if unit.mode.is_rustc_test()
1219+
&& !(unit.target.is_test() || unit.target.is_bench())
1220+
{
1221+
command.push_str(" --tests");
1222+
}
1223+
let mut suggestions = format!("{} suggestion", n);
1224+
if n > 1 {
1225+
suggestions.push_str("s")
1226+
}
1227+
drop(write!(
1228+
message,
1229+
" (run `cargo fix --{}` to apply {})",
1230+
command, suggestions
1231+
))
1232+
}
1233+
}
1234+
}
1235+
}
11631236
// Errors are ignored here because it is tricky to handle them
11641237
// correctly, and they aren't important.
11651238
drop(config.shell().warn(message));

src/cargo/core/compiler/mod.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ use crate::util::interning::InternedString;
6161
use crate::util::machine_message::{self, Message};
6262
use crate::util::{add_path_args, internal, iter_join_onto, profile};
6363
use cargo_util::{paths, ProcessBuilder, ProcessError};
64+
use rustfix::diagnostics::{Applicability, Diagnostic};
6465

6566
const RUSTDOC_CRATE_VERSION_FLAG: &str = "--crate-version";
6667

@@ -1420,7 +1421,9 @@ fn on_stderr_line_inner(
14201421
rendered: String,
14211422
message: String,
14221423
level: String,
1424+
children: Vec<Diagnostic>,
14231425
}
1426+
14241427
if let Ok(mut msg) = serde_json::from_str::<CompilerMessage>(compiler_message.get()) {
14251428
if msg.message.starts_with("aborting due to")
14261429
|| msg.message.ends_with("warning emitted")
@@ -1443,8 +1446,19 @@ fn on_stderr_line_inner(
14431446
.expect("strip should never fail")
14441447
};
14451448
if options.show_diagnostics {
1449+
let machine_applicable: bool = msg
1450+
.children
1451+
.iter()
1452+
.map(|child| {
1453+
child
1454+
.spans
1455+
.iter()
1456+
.filter_map(|span| span.suggestion_applicability)
1457+
.any(|app| app == Applicability::MachineApplicable)
1458+
})
1459+
.any(|b| b);
14461460
count_diagnostic(&msg.level, options);
1447-
state.emit_diag(msg.level, rendered)?;
1461+
state.emit_diag(msg.level, rendered, machine_applicable)?;
14481462
}
14491463
return Ok(true);
14501464
}

0 commit comments

Comments
 (0)