@@ -10,7 +10,7 @@ use hir_expand::proc_macro::{
10
10
ProcMacros ,
11
11
} ;
12
12
use ide_db:: {
13
- base_db:: { CrateGraph , Env , SourceRoot } ,
13
+ base_db:: { CrateGraph , Env , SourceRoot , SourceRootId } ,
14
14
prime_caches, ChangeWithProcMacros , FxHashMap , RootDatabase ,
15
15
} ;
16
16
use itertools:: Itertools ;
@@ -231,7 +231,7 @@ impl ProjectFolders {
231
231
res. load . push ( entry) ;
232
232
233
233
if root. is_local {
234
- local_filesets. push ( fsc. len ( ) ) ;
234
+ local_filesets. push ( fsc. len ( ) as u64 ) ;
235
235
}
236
236
fsc. add_file_set ( file_set_roots)
237
237
}
@@ -246,7 +246,7 @@ impl ProjectFolders {
246
246
#[ derive( Default , Debug ) ]
247
247
pub struct SourceRootConfig {
248
248
pub fsc : FileSetConfig ,
249
- pub local_filesets : Vec < usize > ,
249
+ pub local_filesets : Vec < u64 > ,
250
250
}
251
251
252
252
impl SourceRootConfig {
@@ -256,7 +256,7 @@ impl SourceRootConfig {
256
256
. into_iter ( )
257
257
. enumerate ( )
258
258
. map ( |( idx, file_set) | {
259
- let is_local = self . local_filesets . contains ( & idx) ;
259
+ let is_local = self . local_filesets . contains ( & ( idx as u64 ) ) ;
260
260
if is_local {
261
261
SourceRoot :: new_local ( file_set)
262
262
} else {
@@ -265,6 +265,36 @@ impl SourceRootConfig {
265
265
} )
266
266
. collect ( )
267
267
}
268
+
269
+ /// Maps local source roots to their parent source roots by bytewise comparing of root paths .
270
+ /// If a source root doesn't have a parent then its parent is declared as None.
271
+ pub fn source_root_parent_map ( & self ) -> FxHashMap < SourceRootId , Option < SourceRootId > > {
272
+ let roots = self . fsc . roots ( ) ;
273
+ let mut map = FxHashMap :: < SourceRootId , Option < SourceRootId > > :: default ( ) ;
274
+
275
+ ' outer: for ( idx, ( root, root_id) ) in roots. iter ( ) . enumerate ( ) {
276
+ if !self . local_filesets . contains ( root_id) {
277
+ continue ;
278
+ }
279
+
280
+ for ( _, ( root2, root2_id) ) in roots. iter ( ) . enumerate ( ) . take ( idx) . rev ( ) {
281
+ if root2. iter ( ) . enumerate ( ) . all ( |( i, c) | & root[ i] == c) {
282
+ // We are interested in parents if they are also local source roots.
283
+ // So instead of a non-local parent we may take a local ancestor as a parent to a node.
284
+ if self . local_filesets . contains ( root2_id) {
285
+ map. insert (
286
+ SourceRootId ( root_id. to_owned ( ) as u32 ) ,
287
+ Some ( SourceRootId ( root2_id. to_owned ( ) as u32 ) ) ,
288
+ ) ;
289
+ continue ' outer;
290
+ }
291
+ }
292
+ }
293
+ map. insert ( SourceRootId ( idx as u32 ) , None ) ;
294
+ }
295
+
296
+ map
297
+ }
268
298
}
269
299
270
300
/// Load the proc-macros for the given lib path, replacing all expanders whose names are in `dummy_replace`
@@ -413,4 +443,203 @@ mod tests {
413
443
// RA has quite a few crates, but the exact count doesn't matter
414
444
assert ! ( n_crates > 20 ) ;
415
445
}
446
+
447
+ mod source_root_parent {
448
+ use ide_db:: base_db:: SourceRootId ;
449
+ use vfs:: { file_set:: FileSetConfigBuilder , VfsPath } ;
450
+
451
+ use crate :: SourceRootConfig ;
452
+
453
+ macro_rules! virp {
454
+ ( $s : literal) => {
455
+ VfsPath :: new_virtual_path( format!( $s) )
456
+ } ;
457
+ }
458
+
459
+ #[ test]
460
+ fn test1 ( ) {
461
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
462
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
463
+ let root2 = vec ! [ virp!( "/ROOT/def" ) ] ;
464
+ builder. add_file_set ( root) ;
465
+ builder. add_file_set ( root2) ;
466
+ let fsc = builder. build ( ) ;
467
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 ] } ;
468
+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
469
+
470
+ assert_eq ! ( vc, vec![ ( SourceRootId ( 0 ) , None ) , ( SourceRootId ( 1 ) , None ) ] )
471
+ }
472
+
473
+ #[ test]
474
+ fn test2 ( ) {
475
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
476
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
477
+ let root2 = vec ! [ virp!( "/ROOT/def/abc" ) ] ;
478
+ builder. add_file_set ( root) ;
479
+ builder. add_file_set ( root2) ;
480
+ let fsc = builder. build ( ) ;
481
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 ] } ;
482
+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
483
+
484
+ assert_eq ! ( vc, vec![ ( SourceRootId ( 0 ) , None ) , ( SourceRootId ( 1 ) , None ) ] )
485
+ }
486
+
487
+ #[ test]
488
+ fn test3 ( ) {
489
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
490
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
491
+ let root2 = vec ! [ virp!( "/ROOT/abc/def" ) ] ;
492
+ builder. add_file_set ( root) ;
493
+ builder. add_file_set ( root2) ;
494
+ let fsc = builder. build ( ) ;
495
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 ] } ;
496
+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
497
+
498
+ assert_eq ! ( vc, vec![ ( SourceRootId ( 0 ) , None ) , ( SourceRootId ( 1 ) , Some ( SourceRootId ( 0 ) ) ) ] )
499
+ }
500
+
501
+ #[ test]
502
+ fn test4 ( ) {
503
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
504
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
505
+ let root2 = vec ! [ virp!( "/ROOT/def" ) ] ;
506
+ let root3 = vec ! [ virp!( "/ROOT/def/abc" ) ] ;
507
+ builder. add_file_set ( root) ;
508
+ builder. add_file_set ( root2) ;
509
+ builder. add_file_set ( root3) ;
510
+ let fsc = builder. build ( ) ;
511
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 2 ] } ;
512
+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
513
+
514
+ assert_eq ! (
515
+ vc,
516
+ vec![
517
+ ( SourceRootId ( 0 ) , None ) ,
518
+ ( SourceRootId ( 1 ) , None ) ,
519
+ ( SourceRootId ( 2 ) , Some ( SourceRootId ( 1 ) ) )
520
+ ]
521
+ )
522
+ }
523
+
524
+ #[ test]
525
+ fn test5 ( ) {
526
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
527
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
528
+ let root2 = vec ! [ virp!( "/ROOT/ghi" ) ] ;
529
+ let root3 = vec ! [ virp!( "/ROOT/def/abc" ) ] ;
530
+ builder. add_file_set ( root) ;
531
+ builder. add_file_set ( root2) ;
532
+ builder. add_file_set ( root3) ;
533
+ let fsc = builder. build ( ) ;
534
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 2 ] } ;
535
+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
536
+
537
+ assert_eq ! (
538
+ vc,
539
+ vec![ ( SourceRootId ( 0 ) , None ) , ( SourceRootId ( 1 ) , None ) , ( SourceRootId ( 2 ) , None ) ]
540
+ )
541
+ }
542
+
543
+ #[ test]
544
+ fn test6 ( ) {
545
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
546
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
547
+ let root2 = vec ! [ virp!( "/ROOT/def" ) ] ;
548
+ let root3 = vec ! [ virp!( "/ROOT/def/ghi/jkl" ) ] ;
549
+ builder. add_file_set ( root) ;
550
+ builder. add_file_set ( root2) ;
551
+ builder. add_file_set ( root3) ;
552
+ let fsc = builder. build ( ) ;
553
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 2 ] } ;
554
+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
555
+
556
+ assert_eq ! (
557
+ vc,
558
+ vec![
559
+ ( SourceRootId ( 0 ) , None ) ,
560
+ ( SourceRootId ( 1 ) , None ) ,
561
+ ( SourceRootId ( 2 ) , Some ( SourceRootId ( 1 ) ) )
562
+ ]
563
+ )
564
+ }
565
+
566
+ #[ test]
567
+ fn test7 ( ) {
568
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
569
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
570
+ let root2 = vec ! [ virp!( "/ROOT/def" ) ] ;
571
+ let root3 = vec ! [ virp!( "/ROOT/def/ghi/jkl" ) ] ;
572
+ let root4 = vec ! [ virp!( "/ROOT/def/ghi/klm" ) ] ;
573
+ builder. add_file_set ( root) ;
574
+ builder. add_file_set ( root2) ;
575
+ builder. add_file_set ( root3) ;
576
+ builder. add_file_set ( root4) ;
577
+ let fsc = builder. build ( ) ;
578
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 2 , 3 ] } ;
579
+ let mut vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
580
+ vc. sort_by ( |x, y| x. 0 . 0 . cmp ( & y. 0 . 0 ) ) ;
581
+
582
+ assert_eq ! (
583
+ vc,
584
+ vec![
585
+ ( SourceRootId ( 0 ) , None ) ,
586
+ ( SourceRootId ( 1 ) , None ) ,
587
+ ( SourceRootId ( 2 ) , Some ( SourceRootId ( 1 ) ) ) ,
588
+ ( SourceRootId ( 3 ) , Some ( SourceRootId ( 1 ) ) )
589
+ ]
590
+ )
591
+ }
592
+
593
+ #[ test]
594
+ fn test8 ( ) {
595
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
596
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
597
+ let root2 = vec ! [ virp!( "/ROOT/def" ) ] ;
598
+ let root3 = vec ! [ virp!( "/ROOT/def/ghi/jkl" ) ] ;
599
+ let root4 = vec ! [ virp!( "/ROOT/def/klm" ) ] ;
600
+ builder. add_file_set ( root) ;
601
+ builder. add_file_set ( root2) ;
602
+ builder. add_file_set ( root3) ;
603
+ builder. add_file_set ( root4) ;
604
+ let fsc = builder. build ( ) ;
605
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 3 ] } ;
606
+ let mut vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
607
+ vc. sort_by ( |x, y| x. 0 . 0 . cmp ( & y. 0 . 0 ) ) ;
608
+
609
+ assert_eq ! (
610
+ vc,
611
+ vec![
612
+ ( SourceRootId ( 0 ) , None ) ,
613
+ ( SourceRootId ( 1 ) , None ) ,
614
+ ( SourceRootId ( 3 ) , Some ( SourceRootId ( 1 ) ) ) ,
615
+ ]
616
+ )
617
+ }
618
+
619
+ #[ test]
620
+ fn test9 ( ) {
621
+ let mut builder = FileSetConfigBuilder :: default ( ) ;
622
+ let root = vec ! [ virp!( "/ROOT/abc" ) ] ;
623
+ let root2 = vec ! [ virp!( "/ROOT/def" ) ] ;
624
+ let root3 = vec ! [ virp!( "/ROOT/def/klm" ) ] ;
625
+ let root4 = vec ! [ virp!( "/ROOT/def/klm/jkl" ) ] ;
626
+ builder. add_file_set ( root) ;
627
+ builder. add_file_set ( root2) ;
628
+ builder. add_file_set ( root3) ;
629
+ builder. add_file_set ( root4) ;
630
+ let fsc = builder. build ( ) ;
631
+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 3 ] } ;
632
+ let mut vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
633
+ vc. sort_by ( |x, y| x. 0 . 0 . cmp ( & y. 0 . 0 ) ) ;
634
+
635
+ assert_eq ! (
636
+ vc,
637
+ vec![
638
+ ( SourceRootId ( 0 ) , None ) ,
639
+ ( SourceRootId ( 1 ) , None ) ,
640
+ ( SourceRootId ( 3 ) , Some ( SourceRootId ( 1 ) ) ) ,
641
+ ]
642
+ )
643
+ }
644
+ }
416
645
}
0 commit comments