1
1
//! Flycheck provides the functionality needed to run `cargo check` to provide
2
2
//! LSP diagnostics based on the output of the command.
3
3
4
- use std:: { fmt, io, process:: Command , time:: Duration } ;
4
+ use std:: { fmt, io, mem , process:: Command , time:: Duration } ;
5
5
6
+ use cargo_metadata:: PackageId ;
6
7
use crossbeam_channel:: { select_biased, unbounded, Receiver , Sender } ;
7
8
use paths:: { AbsPath , AbsPathBuf , Utf8PathBuf } ;
8
9
use rustc_hash:: FxHashMap ;
@@ -150,10 +151,19 @@ impl FlycheckHandle {
150
151
151
152
pub ( crate ) enum FlycheckMessage {
152
153
/// Request adding a diagnostic with fixes included to a file
153
- AddDiagnostic { id : usize , workspace_root : AbsPathBuf , diagnostic : Diagnostic } ,
154
+ AddDiagnostic {
155
+ id : usize ,
156
+ workspace_root : AbsPathBuf ,
157
+ diagnostic : Diagnostic ,
158
+ package_id : Option < PackageId > ,
159
+ } ,
154
160
155
- /// Request clearing all previous diagnostics
156
- ClearDiagnostics { id : usize } ,
161
+ /// Request clearing all outdated diagnostics.
162
+ ClearDiagnostics {
163
+ id : usize ,
164
+ /// The pacakge whose diagnostics to clear, or if unspecified, all diagnostics.
165
+ package_id : Option < PackageId > ,
166
+ } ,
157
167
158
168
/// Request check progress notification to client
159
169
Progress {
@@ -166,15 +176,18 @@ pub(crate) enum FlycheckMessage {
166
176
impl fmt:: Debug for FlycheckMessage {
167
177
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
168
178
match self {
169
- FlycheckMessage :: AddDiagnostic { id, workspace_root, diagnostic } => f
179
+ FlycheckMessage :: AddDiagnostic { id, workspace_root, diagnostic, package_id } => f
170
180
. debug_struct ( "AddDiagnostic" )
171
181
. field ( "id" , id)
172
182
. field ( "workspace_root" , workspace_root)
183
+ . field ( "package_id" , package_id)
173
184
. field ( "diagnostic_code" , & diagnostic. code . as_ref ( ) . map ( |it| & it. code ) )
174
185
. finish ( ) ,
175
- FlycheckMessage :: ClearDiagnostics { id } => {
176
- f. debug_struct ( "ClearDiagnostics" ) . field ( "id" , id) . finish ( )
177
- }
186
+ FlycheckMessage :: ClearDiagnostics { id, package_id } => f
187
+ . debug_struct ( "ClearDiagnostics" )
188
+ . field ( "id" , id)
189
+ . field ( "package_id" , package_id)
190
+ . finish ( ) ,
178
191
FlycheckMessage :: Progress { id, progress } => {
179
192
f. debug_struct ( "Progress" ) . field ( "id" , id) . field ( "progress" , progress) . finish ( )
180
193
}
@@ -200,6 +213,7 @@ enum StateChange {
200
213
struct FlycheckActor {
201
214
/// The workspace id of this flycheck instance.
202
215
id : usize ,
216
+
203
217
sender : Sender < FlycheckMessage > ,
204
218
config : FlycheckConfig ,
205
219
manifest_path : Option < AbsPathBuf > ,
@@ -215,8 +229,13 @@ struct FlycheckActor {
215
229
command_handle : Option < CommandHandle < CargoCheckMessage > > ,
216
230
/// The receiver side of the channel mentioned above.
217
231
command_receiver : Option < Receiver < CargoCheckMessage > > ,
232
+ package_status : FxHashMap < PackageId , DiagnosticReceived > ,
233
+ }
218
234
219
- status : FlycheckStatus ,
235
+ #[ derive( PartialEq , Eq , Copy , Clone , Debug ) ]
236
+ enum DiagnosticReceived {
237
+ Yes ,
238
+ No ,
220
239
}
221
240
222
241
#[ allow( clippy:: large_enum_variant) ]
@@ -225,13 +244,6 @@ enum Event {
225
244
CheckEvent ( Option < CargoCheckMessage > ) ,
226
245
}
227
246
228
- #[ derive( PartialEq ) ]
229
- enum FlycheckStatus {
230
- Started ,
231
- DiagnosticSent ,
232
- Finished ,
233
- }
234
-
235
247
pub ( crate ) const SAVED_FILE_PLACEHOLDER : & str = "$saved_file" ;
236
248
237
249
impl FlycheckActor {
@@ -253,7 +265,7 @@ impl FlycheckActor {
253
265
manifest_path,
254
266
command_handle : None ,
255
267
command_receiver : None ,
256
- status : FlycheckStatus :: Finished ,
268
+ package_status : FxHashMap :: default ( ) ,
257
269
}
258
270
}
259
271
@@ -306,13 +318,11 @@ impl FlycheckActor {
306
318
self . command_handle = Some ( command_handle) ;
307
319
self . command_receiver = Some ( receiver) ;
308
320
self . report_progress ( Progress :: DidStart ) ;
309
- self . status = FlycheckStatus :: Started ;
310
321
}
311
322
Err ( error) => {
312
323
self . report_progress ( Progress :: DidFailToRestart ( format ! (
313
324
"Failed to run the following command: {formatted_command} error={error}"
314
325
) ) ) ;
315
- self . status = FlycheckStatus :: Finished ;
316
326
}
317
327
}
318
328
}
@@ -332,11 +342,25 @@ impl FlycheckActor {
332
342
error
333
343
) ;
334
344
}
335
- if self . status == FlycheckStatus :: Started {
336
- self . send ( FlycheckMessage :: ClearDiagnostics { id : self . id } ) ;
345
+ if self . package_status . is_empty ( ) {
346
+ // We finished without receiving any diagnostics.
347
+ // That means all of them are stale.
348
+ self . send ( FlycheckMessage :: ClearDiagnostics {
349
+ id : self . id ,
350
+ package_id : None ,
351
+ } ) ;
352
+ } else {
353
+ for ( package_id, status) in mem:: take ( & mut self . package_status ) {
354
+ if let DiagnosticReceived :: No = status {
355
+ self . send ( FlycheckMessage :: ClearDiagnostics {
356
+ id : self . id ,
357
+ package_id : Some ( package_id) ,
358
+ } ) ;
359
+ }
360
+ }
337
361
}
362
+
338
363
self . report_progress ( Progress :: DidFinish ( res) ) ;
339
- self . status = FlycheckStatus :: Finished ;
340
364
}
341
365
Event :: CheckEvent ( Some ( message) ) => match message {
342
366
CargoCheckMessage :: CompilerArtifact ( msg) => {
@@ -346,23 +370,30 @@ impl FlycheckActor {
346
370
"artifact received"
347
371
) ;
348
372
self . report_progress ( Progress :: DidCheckCrate ( msg. target . name ) ) ;
373
+ self . package_status . entry ( msg. package_id ) . or_insert ( DiagnosticReceived :: No ) ;
349
374
}
350
-
351
- CargoCheckMessage :: Diagnostic ( msg) => {
375
+ CargoCheckMessage :: Diagnostic { diagnostic, package_id } => {
352
376
tracing:: trace!(
353
377
flycheck_id = self . id,
354
- message = msg . message,
378
+ message = diagnostic . message,
355
379
"diagnostic received"
356
380
) ;
357
- if self . status == FlycheckStatus :: Started {
358
- self . send ( FlycheckMessage :: ClearDiagnostics { id : self . id } ) ;
381
+ if let Some ( package_id) = & package_id {
382
+ if !self . package_status . contains_key ( package_id) {
383
+ self . package_status
384
+ . insert ( package_id. clone ( ) , DiagnosticReceived :: Yes ) ;
385
+ self . send ( FlycheckMessage :: ClearDiagnostics {
386
+ id : self . id ,
387
+ package_id : Some ( package_id. clone ( ) ) ,
388
+ } ) ;
389
+ }
359
390
}
360
391
self . send ( FlycheckMessage :: AddDiagnostic {
361
392
id : self . id ,
393
+ package_id,
362
394
workspace_root : self . root . clone ( ) ,
363
- diagnostic : msg ,
395
+ diagnostic,
364
396
} ) ;
365
- self . status = FlycheckStatus :: DiagnosticSent ;
366
397
}
367
398
} ,
368
399
}
@@ -380,7 +411,7 @@ impl FlycheckActor {
380
411
command_handle. cancel ( ) ;
381
412
self . command_receiver . take ( ) ;
382
413
self . report_progress ( Progress :: DidCancel ) ;
383
- self . status = FlycheckStatus :: Finished ;
414
+ self . package_status . clear ( ) ;
384
415
}
385
416
}
386
417
@@ -486,7 +517,7 @@ impl FlycheckActor {
486
517
#[ allow( clippy:: large_enum_variant) ]
487
518
enum CargoCheckMessage {
488
519
CompilerArtifact ( cargo_metadata:: Artifact ) ,
489
- Diagnostic ( Diagnostic ) ,
520
+ Diagnostic { diagnostic : Diagnostic , package_id : Option < PackageId > } ,
490
521
}
491
522
492
523
impl ParseFromLine for CargoCheckMessage {
@@ -501,11 +532,16 @@ impl ParseFromLine for CargoCheckMessage {
501
532
Some ( CargoCheckMessage :: CompilerArtifact ( artifact) )
502
533
}
503
534
cargo_metadata:: Message :: CompilerMessage ( msg) => {
504
- Some ( CargoCheckMessage :: Diagnostic ( msg. message ) )
535
+ Some ( CargoCheckMessage :: Diagnostic {
536
+ diagnostic : msg. message ,
537
+ package_id : Some ( msg. package_id ) ,
538
+ } )
505
539
}
506
540
_ => None ,
507
541
} ,
508
- JsonMessage :: Rustc ( message) => Some ( CargoCheckMessage :: Diagnostic ( message) ) ,
542
+ JsonMessage :: Rustc ( message) => {
543
+ Some ( CargoCheckMessage :: Diagnostic { diagnostic : message, package_id : None } )
544
+ }
509
545
} ;
510
546
}
511
547
0 commit comments