@@ -209,6 +209,7 @@ impl ConfigDb {
209
209
. iter ( )
210
210
. flat_map ( |path : & AbsPathBuf | {
211
211
path. ancestors ( )
212
+ // Note that Path::new("/root2/abc").starts_with(Path::new("/root")) is false
212
213
. take_while ( |x| x. starts_with ( & self . project_root ) )
213
214
. map ( |dir| dir. join ( "rust-analyzer.toml" ) )
214
215
. map ( |path| vfs. alloc_file_id ( path. into ( ) ) )
@@ -236,7 +237,17 @@ impl ConfigDb {
236
237
}
237
238
}
238
239
239
- // Could delete (self.known_file_ids - parent_changes.keys) here.
240
+ // Remove source roots (& their parent config files) that are no longer part of the project root
241
+ self . known_file_ids
242
+ . iter ( )
243
+ . cloned ( )
244
+ . filter ( |& x| x != self . xdg_config_file_id && !parent_changes. contains_key ( & x) )
245
+ . collect_vec ( )
246
+ . into_iter ( )
247
+ . for_each ( |deleted| {
248
+ self . known_file_ids . remove ( & deleted) ;
249
+ self . reset_node ( deleted) ;
250
+ } ) ;
240
251
241
252
let inner = ConfigChangesInner {
242
253
ra_toml_changes : changes. ra_toml_changes ,
@@ -307,17 +318,17 @@ impl ConfigDb {
307
318
/// if it's never been seen before
308
319
fn ensure_node ( & mut self , file_id : FileId ) {
309
320
if self . known_file_ids . insert ( file_id) {
310
- self . set_config_input ( file_id, None ) ;
311
- self . set_parent (
312
- file_id,
313
- if file_id == self . xdg_config_file_id {
314
- None
315
- } else {
316
- Some ( self . xdg_config_file_id )
317
- } ,
318
- ) ;
321
+ self . reset_node ( file_id) ;
319
322
}
320
323
}
324
+
325
+ fn reset_node ( & mut self , file_id : FileId ) {
326
+ self . set_config_input ( file_id, None ) ;
327
+ self . set_parent (
328
+ file_id,
329
+ if file_id == self . xdg_config_file_id { None } else { Some ( self . xdg_config_file_id ) } ,
330
+ ) ;
331
+ }
321
332
}
322
333
323
334
fn parse_toml (
@@ -527,7 +538,7 @@ mod tests {
527
538
528
539
// Now move crate b to the root. This gives a new FileId for crate_b/ra.toml.
529
540
let source_roots = [ "/root/crate_a" , "/root/crate_b" ] . map ( Path :: new) . map ( AbsPath :: assert) ;
530
- let [ crate_a , crate_b] = source_roots
541
+ let [ _crate_a , crate_b] = source_roots
531
542
. map ( |dir| dir. join ( "rust-analyzer.toml" ) )
532
543
. map ( |path| vfs. alloc_file_id ( path. into ( ) ) ) ;
533
544
let new_source_roots = source_roots. into_iter ( ) . map ( |abs| abs. to_path_buf ( ) ) . collect ( ) ;
@@ -549,4 +560,53 @@ mod tests {
549
560
// new crate_b does not inherit from crate_a
550
561
assert_eq ! ( local. completion_autoself_enable, true ) ;
551
562
}
563
+
564
+ #[ test]
565
+ fn change_project_root ( ) {
566
+ tracing_subscriber:: fmt ( ) . try_init ( ) . ok ( ) ;
567
+ let mut vfs = Vfs :: default ( ) ;
568
+
569
+ let project_root = AbsPath :: assert ( Path :: new ( "/root" ) ) ;
570
+ let xdg =
571
+ alloc_file_id ( & mut vfs, "/home/username/.config/rust-analyzer/rust-analyzer.toml" ) ;
572
+ let mut config_tree = ConfigDb :: new ( xdg, project_root. to_path_buf ( ) ) ;
573
+
574
+ let source_roots = [ "/root/crate_a" ] . map ( Path :: new) . map ( AbsPath :: assert) ;
575
+ let crate_a = vfs. alloc_file_id ( source_roots[ 0 ] . join ( "rust-analyzer.toml" ) . into ( ) ) ;
576
+
577
+ let _root = alloc_config (
578
+ & mut vfs,
579
+ "/root/rust-analyzer.toml" ,
580
+ r#"
581
+ [completion.autoself]
582
+ enable = false
583
+ "# ,
584
+ ) ;
585
+
586
+ let new_source_roots = source_roots. into_iter ( ) . map ( |abs| abs. to_path_buf ( ) ) . collect ( ) ;
587
+ let changes = ConfigChanges {
588
+ client_change : None ,
589
+ set_project_root : None , // already set in ConfigDb::new(...)
590
+ set_source_roots : Some ( new_source_roots) ,
591
+ ra_toml_changes : dbg ! ( vfs. take_changes( ) ) ,
592
+ } ;
593
+ config_tree. apply_changes ( changes, & mut vfs) ;
594
+ let local = config_tree. local_config ( crate_a) ;
595
+ // initially crate_a is part of the project root, so it does inherit
596
+ // from /root/rust-analyzer.toml
597
+ assert_eq ! ( local. completion_autoself_enable, false ) ;
598
+
599
+ // change project root
600
+ let changes = ConfigChanges {
601
+ client_change : None ,
602
+ set_project_root : Some ( AbsPath :: assert ( Path :: new ( "/ro" ) ) . to_path_buf ( ) ) ,
603
+ set_source_roots : None ,
604
+ ra_toml_changes : dbg ! ( vfs. take_changes( ) ) ,
605
+ } ;
606
+ config_tree. apply_changes ( changes, & mut vfs) ;
607
+ // crate_a is now outside the project root and hence inherit (1) xdg (2)
608
+ // crate_a/ra.toml, but not /root/rust-analyzer.toml any more
609
+ let local = config_tree. local_config ( crate_a) ;
610
+ assert_eq ! ( local. completion_autoself_enable, true ) ;
611
+ }
552
612
}
0 commit comments