@@ -128,16 +128,45 @@ pub trait ProgressReporter: Send + Sync {
128
128
fn set_files ( & mut self , files : usize ) ;
129
129
130
130
/// Report the completion of a given file.
131
- fn report_file ( & self , file : & File ) ;
131
+ fn report_file ( & self , db : & dyn Db , file : File , diagnostics : & [ Diagnostic ] ) ;
132
+
133
+ /// Reports settings or IO related diagnostics. The diagnostics
134
+ /// can belong to different files or no file at all.
135
+ /// But it's never a file for which [`Self::report_file`] gets called.
136
+ fn report_diagnostics ( & mut self , db : & dyn Db , diagnostics : Vec < Diagnostic > ) ;
132
137
}
133
138
134
- /// A no-op implementation of [`ProgressReporter`] .
139
+ /// Reporter that collects all diagnostics into a `Vec` .
135
140
#[ derive( Default ) ]
136
- pub struct DummyReporter ;
141
+ pub struct CollectReporter ( std:: sync:: Mutex < Vec < Diagnostic > > ) ;
142
+
143
+ impl CollectReporter {
144
+ pub fn into_sorted ( self , db : & dyn Db ) -> Vec < Diagnostic > {
145
+ let mut diagnostics = self . 0 . into_inner ( ) . unwrap ( ) ;
146
+ diagnostics. sort_by ( |left, right| {
147
+ left. rendering_sort_key ( db)
148
+ . cmp ( & right. rendering_sort_key ( db) )
149
+ } ) ;
150
+ diagnostics
151
+ }
152
+ }
137
153
138
- impl ProgressReporter for DummyReporter {
154
+ impl ProgressReporter for CollectReporter {
139
155
fn set_files ( & mut self , _files : usize ) { }
140
- fn report_file ( & self , _file : & File ) { }
156
+ fn report_file ( & self , _db : & dyn Db , _file : File , diagnostics : & [ Diagnostic ] ) {
157
+ if diagnostics. is_empty ( ) {
158
+ return ;
159
+ }
160
+
161
+ self . 0
162
+ . lock ( )
163
+ . unwrap ( )
164
+ . extend ( diagnostics. iter ( ) . map ( Clone :: clone) ) ;
165
+ }
166
+
167
+ fn report_diagnostics ( & mut self , _db : & dyn Db , diagnostics : Vec < Diagnostic > ) {
168
+ self . 0 . get_mut ( ) . unwrap ( ) . extend ( diagnostics) ;
169
+ }
141
170
}
142
171
143
172
#[ salsa:: tracked]
@@ -225,11 +254,7 @@ impl Project {
225
254
}
226
255
227
256
/// Checks the project and its dependencies according to the project's check mode.
228
- pub ( crate ) fn check (
229
- self ,
230
- db : & ProjectDatabase ,
231
- reporter : & mut dyn ProgressReporter ,
232
- ) -> Vec < Diagnostic > {
257
+ pub ( crate ) fn check ( self , db : & ProjectDatabase , reporter : & mut dyn ProgressReporter ) {
233
258
let project_span = tracing:: debug_span!( "Project::check" ) ;
234
259
let _span = project_span. enter ( ) ;
235
260
@@ -239,12 +264,11 @@ impl Project {
239
264
name = self . name( db)
240
265
) ;
241
266
242
- let mut diagnostics: Vec < Diagnostic > = Vec :: new ( ) ;
243
- diagnostics. extend (
244
- self . settings_diagnostics ( db)
245
- . iter ( )
246
- . map ( OptionDiagnostic :: to_diagnostic) ,
247
- ) ;
267
+ let mut diagnostics: Vec < Diagnostic > = self
268
+ . settings_diagnostics ( db)
269
+ . iter ( )
270
+ . map ( OptionDiagnostic :: to_diagnostic)
271
+ . collect ( ) ;
248
272
249
273
let files = ProjectFiles :: new ( db, self ) ;
250
274
reporter. set_files ( files. len ( ) ) ;
@@ -256,30 +280,27 @@ impl Project {
256
280
. map ( IOErrorDiagnostic :: to_diagnostic) ,
257
281
) ;
258
282
283
+ reporter. report_diagnostics ( db, diagnostics) ;
284
+
259
285
let open_files = self . open_files ( db) ;
260
286
let check_start = ruff_db:: Instant :: now ( ) ;
261
- let file_diagnostics = std:: sync:: Mutex :: new ( vec ! [ ] ) ;
262
287
263
288
{
264
289
let db = db. clone ( ) ;
265
- let file_diagnostics = & file_diagnostics;
266
290
let project_span = & project_span;
267
- let reporter = & reporter;
268
291
269
292
rayon:: scope ( move |scope| {
270
293
for file in & files {
271
294
let db = db. clone ( ) ;
295
+ let reporter = & * reporter;
272
296
scope. spawn ( move |_| {
273
297
let check_file_span =
274
298
tracing:: debug_span!( parent: project_span, "check_file" , ?file) ;
275
299
let _entered = check_file_span. entered ( ) ;
276
300
277
301
match check_file_impl ( & db, file) {
278
302
Ok ( diagnostics) => {
279
- file_diagnostics
280
- . lock ( )
281
- . unwrap ( )
282
- . extend ( diagnostics. iter ( ) . map ( Clone :: clone) ) ;
303
+ reporter. report_file ( & db, file, diagnostics) ;
283
304
284
305
// This is outside `check_file_impl` to avoid that opening or closing
285
306
// a file invalidates the `check_file_impl` query of every file!
@@ -295,28 +316,18 @@ impl Project {
295
316
}
296
317
}
297
318
Err ( io_error) => {
298
- file_diagnostics . lock ( ) . unwrap ( ) . push ( io_error. clone ( ) ) ;
319
+ reporter . report_file ( & db , file , std :: slice :: from_ref ( io_error) ) ;
299
320
}
300
321
}
301
-
302
- reporter. report_file ( & file) ;
303
322
} ) ;
304
323
}
305
324
} ) ;
306
- }
325
+ } ;
307
326
308
327
tracing:: debug!(
309
328
"Checking all files took {:.3}s" ,
310
329
check_start. elapsed( ) . as_secs_f64( ) ,
311
330
) ;
312
-
313
- let mut file_diagnostics = file_diagnostics. into_inner ( ) . unwrap ( ) ;
314
- file_diagnostics. sort_by ( |left, right| {
315
- left. rendering_sort_key ( db)
316
- . cmp ( & right. rendering_sort_key ( db) )
317
- } ) ;
318
- diagnostics. extend ( file_diagnostics) ;
319
- diagnostics
320
331
}
321
332
322
333
pub ( crate ) fn check_file ( self , db : & dyn Db , file : File ) -> Vec < Diagnostic > {
0 commit comments