@@ -129,12 +129,8 @@ struct DrainState<'cfg> {
129
129
messages : Arc < Queue < Message > > ,
130
130
/// Diagnostic deduplication support.
131
131
diag_dedupe : DiagDedupe < ' cfg > ,
132
- /// Count of warnings, used to print a summary after the job succeeds.
133
- ///
134
- /// First value is the total number of warnings, and the second value is
135
- /// the number that were suppressed because they were duplicates of a
136
- /// previous warning.
137
- warning_count : HashMap < JobId , ( usize , usize ) > ,
132
+ /// Count of warnings, used to print a summary after the job succeeds
133
+ warning_count : HashMap < JobId , WarningCount > ,
138
134
active : HashMap < JobId , Unit > ,
139
135
compiled : HashSet < PackageId > ,
140
136
documented : HashSet < PackageId > ,
@@ -170,6 +166,49 @@ struct DrainState<'cfg> {
170
166
per_package_future_incompat_reports : Vec < FutureIncompatReportPackage > ,
171
167
}
172
168
169
+ /// Count of warnings, used to print a summary after the job succeeds
170
+ #[ derive( Default ) ]
171
+ pub struct WarningCount {
172
+ /// total number of warnings
173
+ pub total : usize ,
174
+ /// number of warnings that were suppressed because they
175
+ /// were duplicates of a previous warning
176
+ pub duplicates : usize ,
177
+ /// number of fixable warnings
178
+ /// set to -1 if there are any errors
179
+ pub fixable : FixableWarnings ,
180
+ }
181
+
182
+ impl WarningCount {
183
+ /// If an error is seem this should be called
184
+ /// to set the `fixable` count to -1 or
185
+ /// no fixable warnings allowed
186
+ fn disallow_fixable ( & mut self ) {
187
+ self . fixable = FixableWarnings :: NowAllowed ;
188
+ }
189
+
190
+ /// Checks fixable if warnings are allowed
191
+ /// fixable warnings are allowed if there are no
192
+ /// errors. If an error was seen `fixable`
193
+ /// will be -1.
194
+ fn fixable_allowed ( & self ) -> bool {
195
+ match & self . fixable {
196
+ FixableWarnings :: NowAllowed => false ,
197
+ FixableWarnings :: Positive ( _) | FixableWarnings :: Zero => true ,
198
+ }
199
+ }
200
+ }
201
+
202
+ /// Used to keep track of how many fixable warnings there are
203
+ /// and if fixable warnings are allowed
204
+ #[ derive( Default ) ]
205
+ pub enum FixableWarnings {
206
+ NowAllowed ,
207
+ #[ default]
208
+ Zero ,
209
+ Positive ( usize ) ,
210
+ }
211
+
173
212
pub struct ErrorsDuringDrain {
174
213
pub count : usize ,
175
214
}
@@ -311,10 +350,12 @@ enum Message {
311
350
id : JobId ,
312
351
level : String ,
313
352
diag : String ,
353
+ fixable : bool ,
314
354
} ,
315
355
WarningCount {
316
356
id : JobId ,
317
357
emitted : bool ,
358
+ fixable : bool ,
318
359
} ,
319
360
FixDiagnostic ( diagnostic_server:: Message ) ,
320
361
Token ( io:: Result < Acquired > ) ,
@@ -363,20 +404,22 @@ impl<'a, 'cfg> JobState<'a, 'cfg> {
363
404
Ok ( ( ) )
364
405
}
365
406
366
- pub fn emit_diag ( & self , level : String , diag : String ) -> CargoResult < ( ) > {
407
+ pub fn emit_diag ( & self , level : String , diag : String , fixable : bool ) -> CargoResult < ( ) > {
367
408
if let Some ( dedupe) = self . output {
368
409
let emitted = dedupe. emit_diag ( & diag) ?;
369
410
if level == "warning" {
370
411
self . messages . push ( Message :: WarningCount {
371
412
id : self . id ,
372
413
emitted,
414
+ fixable,
373
415
} ) ;
374
416
}
375
417
} else {
376
418
self . messages . push_bounded ( Message :: Diagnostic {
377
419
id : self . id ,
378
420
level,
379
421
diag,
422
+ fixable,
380
423
} ) ;
381
424
}
382
425
Ok ( ( ) )
@@ -679,14 +722,28 @@ impl<'cfg> DrainState<'cfg> {
679
722
shell. print_ansi_stderr ( err. as_bytes ( ) ) ?;
680
723
shell. err ( ) . write_all ( b"\n " ) ?;
681
724
}
682
- Message :: Diagnostic { id, level, diag } => {
725
+ Message :: Diagnostic {
726
+ id,
727
+ level,
728
+ diag,
729
+ fixable,
730
+ } => {
683
731
let emitted = self . diag_dedupe . emit_diag ( & diag) ?;
684
732
if level == "warning" {
685
- self . bump_warning_count ( id, emitted) ;
733
+ self . bump_warning_count ( id, emitted, fixable) ;
734
+ }
735
+ if level == "error" {
736
+ let cnts = self . warning_count . entry ( id) . or_default ( ) ;
737
+ // If there is an error, the `cargo fix`message should not show
738
+ cnts. disallow_fixable ( ) ;
686
739
}
687
740
}
688
- Message :: WarningCount { id, emitted } => {
689
- self . bump_warning_count ( id, emitted) ;
741
+ Message :: WarningCount {
742
+ id,
743
+ emitted,
744
+ fixable,
745
+ } => {
746
+ self . bump_warning_count ( id, emitted, fixable) ;
690
747
}
691
748
Message :: FixDiagnostic ( msg) => {
692
749
self . print . print ( & msg) ?;
@@ -1127,19 +1184,34 @@ impl<'cfg> DrainState<'cfg> {
1127
1184
Ok ( ( ) )
1128
1185
}
1129
1186
1130
- fn bump_warning_count ( & mut self , id : JobId , emitted : bool ) {
1187
+ fn bump_warning_count ( & mut self , id : JobId , emitted : bool , fixable : bool ) {
1131
1188
let cnts = self . warning_count . entry ( id) . or_default ( ) ;
1132
- cnts. 0 += 1 ;
1189
+ cnts. total += 1 ;
1133
1190
if !emitted {
1134
- cnts. 1 += 1 ;
1191
+ cnts. duplicates += 1 ;
1192
+ // Don't add to fixable if it's already been emitted
1193
+ } else if fixable {
1194
+ // Do not add anything to the fixable warning count if
1195
+ // is `-1` since that indicates there was an error while
1196
+ // building this `Unit`
1197
+ if cnts. fixable_allowed ( ) {
1198
+ cnts. fixable = match cnts. fixable {
1199
+ FixableWarnings :: NowAllowed => FixableWarnings :: NowAllowed ,
1200
+ FixableWarnings :: Zero => FixableWarnings :: Positive ( 1 ) ,
1201
+ FixableWarnings :: Positive ( fixable) => FixableWarnings :: Positive ( fixable + 1 ) ,
1202
+ } ;
1203
+ }
1135
1204
}
1136
1205
}
1137
1206
1138
1207
/// Displays a final report of the warnings emitted by a particular job.
1139
1208
fn report_warning_count ( & mut self , config : & Config , id : JobId ) {
1140
1209
let count = match self . warning_count . remove ( & id) {
1141
- Some ( count) => count,
1142
- None => return ,
1210
+ // An error could add an entry for a `Unit`
1211
+ // with 0 warnings but having fixable
1212
+ // warnings be disallowed
1213
+ Some ( count) if count. total > 0 => count,
1214
+ None | Some ( _) => return ,
1143
1215
} ;
1144
1216
let unit = & self . active [ & id] ;
1145
1217
let mut message = format ! ( "`{}` ({}" , unit. pkg. name( ) , unit. target. description_named( ) ) ;
@@ -1151,15 +1223,47 @@ impl<'cfg> DrainState<'cfg> {
1151
1223
message. push_str ( " doc" ) ;
1152
1224
}
1153
1225
message. push_str ( ") generated " ) ;
1154
- match count. 0 {
1226
+ match count. total {
1155
1227
1 => message. push_str ( "1 warning" ) ,
1156
1228
n => drop ( write ! ( message, "{} warnings" , n) ) ,
1157
1229
} ;
1158
- match count. 1 {
1230
+ match count. duplicates {
1159
1231
0 => { }
1160
1232
1 => message. push_str ( " (1 duplicate)" ) ,
1161
1233
n => drop ( write ! ( message, " ({} duplicates)" , n) ) ,
1162
1234
}
1235
+ // Only show the `cargo fix` message if its a local `Unit`
1236
+ if unit. is_local ( ) && config. nightly_features_allowed {
1237
+ // Do not show this if there are any errors or no fixable warnings
1238
+ if let FixableWarnings :: Positive ( fixable) = count. fixable {
1239
+ // `cargo fix` doesnt have an option for custom builds
1240
+ if !unit. target . is_custom_build ( ) {
1241
+ let mut command = {
1242
+ let named = unit. target . description_named ( ) ;
1243
+ // if its a lib we need to add the package to fix
1244
+ if named == "lib" {
1245
+ format ! ( "{} -p {}" , named, unit. pkg. name( ) )
1246
+ } else {
1247
+ named
1248
+ }
1249
+ } ;
1250
+ if unit. mode . is_rustc_test ( )
1251
+ && !( unit. target . is_test ( ) || unit. target . is_bench ( ) )
1252
+ {
1253
+ command. push_str ( " --tests" ) ;
1254
+ }
1255
+ let mut suggestions = format ! ( "{} suggestion" , fixable) ;
1256
+ if fixable > 1 {
1257
+ suggestions. push_str ( "s" )
1258
+ }
1259
+ drop ( write ! (
1260
+ message,
1261
+ " (run `cargo fix --{}` to apply {})" ,
1262
+ command, suggestions
1263
+ ) )
1264
+ }
1265
+ }
1266
+ }
1163
1267
// Errors are ignored here because it is tricky to handle them
1164
1268
// correctly, and they aren't important.
1165
1269
drop ( config. shell ( ) . warn ( message) ) ;
0 commit comments