3
3
//!
4
4
//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
5
5
6
- use std:: time:: Instant ;
6
+ use std:: { collections :: hash_map :: Entry , time:: Instant } ;
7
7
8
8
use crossbeam_channel:: { unbounded, Receiver , Sender } ;
9
9
use flycheck:: FlycheckHandle ;
@@ -21,7 +21,7 @@ use proc_macro_api::ProcMacroServer;
21
21
use project_model:: { CargoWorkspace , ProjectWorkspace , Target , WorkspaceBuildScripts } ;
22
22
use rustc_hash:: { FxHashMap , FxHashSet } ;
23
23
use triomphe:: Arc ;
24
- use vfs:: { AnchoredPathBuf , Vfs } ;
24
+ use vfs:: { AnchoredPathBuf , ChangedFile , Vfs } ;
25
25
26
26
use crate :: {
27
27
config:: { Config , ConfigError } ,
@@ -217,8 +217,8 @@ impl GlobalState {
217
217
pub ( crate ) fn process_changes ( & mut self ) -> bool {
218
218
let _p = profile:: span ( "GlobalState::process_changes" ) ;
219
219
220
- let mut file_changes = FxHashMap :: default ( ) ;
221
- let ( change, changed_files , workspace_structure_change) = {
220
+ let mut file_changes = FxHashMap :: < _ , ( bool , ChangedFile ) > :: default ( ) ;
221
+ let ( change, modified_files , workspace_structure_change) = {
222
222
let mut change = Change :: new ( ) ;
223
223
let mut guard = self . vfs . write ( ) ;
224
224
let changed_files = guard. 0 . take_changes ( ) ;
@@ -233,64 +233,63 @@ impl GlobalState {
233
233
// id that is followed by a delete we actually skip observing the file text from the
234
234
// earlier event, to avoid problems later on.
235
235
for changed_file in changed_files {
236
- use vfs:: ChangeKind :: * ;
237
-
238
- file_changes
239
- . entry ( changed_file. file_id )
240
- . and_modify ( |( change, just_created) | {
241
- // None -> Delete => keep
242
- // Create -> Delete => collapse
243
- //
244
- match ( change, just_created, changed_file. change_kind ) {
236
+ use vfs:: Change :: * ;
237
+ match file_changes. entry ( changed_file. file_id ) {
238
+ Entry :: Occupied ( mut o) => {
239
+ let ( just_created, change) = o. get_mut ( ) ;
240
+ match ( & mut change. change , just_created, changed_file. change ) {
245
241
// latter `Delete` wins
246
242
( change, _, Delete ) => * change = Delete ,
247
243
// merge `Create` with `Create` or `Modify`
248
- ( Create , _, Create | Modify ) => { }
244
+ ( Create ( prev ) , _, Create ( new ) | Modify ( new ) ) => * prev = new ,
249
245
// collapse identical `Modify`es
250
- ( Modify , _, Modify ) => { }
246
+ ( Modify ( prev ) , _, Modify ( new ) ) => * prev = new ,
251
247
// equivalent to `Modify`
252
- ( change @ Delete , just_created, Create ) => {
253
- * change = Modify ;
248
+ ( change @ Delete , just_created, Create ( new ) ) => {
249
+ * change = Modify ( new ) ;
254
250
* just_created = true ;
255
251
}
256
252
// shouldn't occur, but collapse into `Create`
257
- ( change @ Delete , just_created, Modify ) => {
258
- * change = Create ;
253
+ ( change @ Delete , just_created, Modify ( new ) ) => {
254
+ * change = Create ( new ) ;
259
255
* just_created = true ;
260
256
}
261
257
// shouldn't occur, but collapse into `Modify`
262
- ( Modify , _, Create ) => { }
258
+ ( Modify ( prev ) , _, Create ( new ) ) => * prev = new ,
263
259
}
264
- } )
265
- . or_insert ( (
266
- changed_file. change_kind ,
267
- matches ! ( changed_file . change_kind , Create ) ,
268
- ) ) ;
260
+ }
261
+ Entry :: Vacant ( v ) => {
262
+ _ = v . insert ( ( matches ! ( & changed_file. change , Create ( _ ) ) , changed_file ) )
263
+ }
264
+ }
269
265
}
270
266
271
267
let changed_files: Vec < _ > = file_changes
272
268
. into_iter ( )
273
- . filter ( |( _, ( change_kind , just_created ) ) | {
274
- !matches ! ( ( change_kind , just_created ) , ( vfs:: ChangeKind :: Delete , true ) )
269
+ . filter ( |( _, ( just_created , change ) ) | {
270
+ !( * just_created && matches ! ( change . change , vfs:: Change :: Delete ) )
275
271
} )
276
- . map ( |( file_id, ( change_kind , _ ) ) | vfs:: ChangedFile { file_id, change_kind } )
272
+ . map ( |( file_id, ( _ , change ) ) | vfs:: ChangedFile { file_id, ..change } )
277
273
. collect ( ) ;
278
274
279
275
let mut workspace_structure_change = None ;
280
276
// A file was added or deleted
281
277
let mut has_structure_changes = false ;
282
278
let mut bytes = vec ! [ ] ;
283
- for file in & changed_files {
279
+ let mut modified_files = vec ! [ ] ;
280
+ for file in changed_files {
284
281
let vfs_path = & vfs. file_path ( file. file_id ) ;
285
282
if let Some ( path) = vfs_path. as_path ( ) {
286
283
let path = path. to_path_buf ( ) ;
287
- if reload:: should_refresh_for_change ( & path, file. change_kind ) {
284
+ if reload:: should_refresh_for_change ( & path, file. kind ( ) ) {
288
285
workspace_structure_change = Some ( ( path. clone ( ) , false ) ) ;
289
286
}
290
287
if file. is_created_or_deleted ( ) {
291
288
has_structure_changes = true ;
292
289
workspace_structure_change =
293
290
Some ( ( path, self . crate_graph_file_dependencies . contains ( vfs_path) ) ) ;
291
+ } else {
292
+ modified_files. push ( file. file_id ) ;
294
293
}
295
294
}
296
295
@@ -299,10 +298,8 @@ impl GlobalState {
299
298
self . diagnostics . clear_native_for ( file. file_id ) ;
300
299
}
301
300
302
- let text = if file. exists ( ) {
303
- let bytes = vfs. file_contents ( file. file_id ) . to_vec ( ) ;
304
-
305
- String :: from_utf8 ( bytes) . ok ( ) . and_then ( |text| {
301
+ let text = if let vfs:: Change :: Create ( v) | vfs:: Change :: Modify ( v) = file. change {
302
+ String :: from_utf8 ( v) . ok ( ) . and_then ( |text| {
306
303
// FIXME: Consider doing normalization in the `vfs` instead? That allows
307
304
// getting rid of some locking
308
305
let ( text, line_endings) = LineEndings :: normalize ( text) ;
@@ -327,11 +324,10 @@ impl GlobalState {
327
324
let roots = self . source_root_config . partition ( vfs) ;
328
325
change. set_roots ( roots) ;
329
326
}
330
- ( change, changed_files , workspace_structure_change)
327
+ ( change, modified_files , workspace_structure_change)
331
328
} ;
332
329
333
330
self . analysis_host . apply_change ( change) ;
334
-
335
331
{
336
332
let raw_database = self . analysis_host . raw_database ( ) ;
337
333
// FIXME: ideally we should only trigger a workspace fetch for non-library changes
@@ -343,13 +339,12 @@ impl GlobalState {
343
339
force_crate_graph_reload,
344
340
) ;
345
341
}
346
- self . proc_macro_changed =
347
- changed_files. iter ( ) . filter ( |file| !file. is_created_or_deleted ( ) ) . any ( |file| {
348
- let crates = raw_database. relevant_crates ( file. file_id ) ;
349
- let crate_graph = raw_database. crate_graph ( ) ;
342
+ self . proc_macro_changed = modified_files. into_iter ( ) . any ( |file_id| {
343
+ let crates = raw_database. relevant_crates ( file_id) ;
344
+ let crate_graph = raw_database. crate_graph ( ) ;
350
345
351
- crates. iter ( ) . any ( |& krate| crate_graph[ krate] . is_proc_macro )
352
- } ) ;
346
+ crates. iter ( ) . any ( |& krate| crate_graph[ krate] . is_proc_macro )
347
+ } ) ;
353
348
}
354
349
355
350
true
@@ -494,10 +489,6 @@ impl GlobalStateSnapshot {
494
489
} )
495
490
}
496
491
497
- pub ( crate ) fn vfs_memory_usage ( & self ) -> usize {
498
- self . vfs_read ( ) . memory_usage ( )
499
- }
500
-
501
492
pub ( crate ) fn file_exists ( & self , file_id : FileId ) -> bool {
502
493
self . vfs . read ( ) . 0 . exists ( file_id)
503
494
}
0 commit comments