@@ -267,32 +267,27 @@ impl SourceRootConfig {
267267 }
268268
269269 /// 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 > > {
270+ /// If a `SourceRoot` doesn't have a parent and is local then it is not contained in this mapping but it can be asserted that it is a root `SourceRoot` .
271+ pub fn source_root_parent_map ( & self ) -> FxHashMap < SourceRootId , SourceRootId > {
272272 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;
273+ let mut map = FxHashMap :: < SourceRootId , SourceRootId > :: default ( ) ;
274+ roots
275+ . iter ( )
276+ . enumerate ( )
277+ . filter ( |( _, ( _, id) ) | self . local_filesets . contains ( id) )
278+ . filter_map ( |( idx, ( root, root_id) ) | {
279+ // We are interested in parents if they are also local source roots.
280+ // So instead of a non-local parent we may take a local ancestor as a parent to a node.
281+ roots. iter ( ) . take ( idx) . find_map ( |( root2, root2_id) | {
282+ if self . local_filesets . contains ( root2_id) && root. starts_with ( root2) {
283+ return Some ( ( root_id, root2_id) ) ;
290284 }
291- }
292- }
293- map. insert ( SourceRootId ( idx as u32 ) , None ) ;
294- }
295-
285+ None
286+ } )
287+ } )
288+ . for_each ( |( child, parent) | {
289+ map. insert ( SourceRootId ( * child as u32 ) , SourceRootId ( * parent as u32 ) ) ;
290+ } ) ;
296291 map
297292 }
298293}
@@ -427,6 +422,11 @@ mod tests {
427422
428423 use super :: * ;
429424
425+ use ide_db:: base_db:: SourceRootId ;
426+ use vfs:: { file_set:: FileSetConfigBuilder , VfsPath } ;
427+
428+ use crate :: SourceRootConfig ;
429+
430430 #[ test]
431431 fn test_loading_rust_analyzer ( ) {
432432 let path = Path :: new ( env ! ( "CARGO_MANIFEST_DIR" ) ) . parent ( ) . unwrap ( ) . parent ( ) . unwrap ( ) ;
@@ -444,202 +444,123 @@ mod tests {
444444 assert ! ( n_crates > 20 ) ;
445445 }
446446
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- }
447+ #[ test]
448+ fn unrelated_sources ( ) {
449+ let mut builder = FileSetConfigBuilder :: default ( ) ;
450+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
451+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def" . to_owned( ) ) ] ) ;
452+ let fsc = builder. build ( ) ;
453+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 ] } ;
454+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
455+
456+ assert_eq ! ( vc, vec![ ] )
457+ }
472458
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- }
459+ #[ test]
460+ fn unrelated_source_sharing_dirname ( ) {
461+ let mut builder = FileSetConfigBuilder :: default ( ) ;
462+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
463+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/abc" . to_owned( ) ) ] ) ;
464+ let fsc = builder. build ( ) ;
465+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 ] } ;
466+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
467+
468+ assert_eq ! ( vc, vec![ ] )
469+ }
486470
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- }
471+ #[ test]
472+ fn basic_child_parent ( ) {
473+ let mut builder = FileSetConfigBuilder :: default ( ) ;
474+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
475+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc/def" . to_owned( ) ) ] ) ;
476+ let fsc = builder. build ( ) ;
477+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 ] } ;
478+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
479+
480+ assert_eq ! ( vc, vec![ ( SourceRootId ( 1 ) , SourceRootId ( 0 ) ) ] )
481+ }
500482
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- }
483+ #[ test]
484+ fn basic_child_parent_with_unrelated_parents_sib ( ) {
485+ let mut builder = FileSetConfigBuilder :: default ( ) ;
486+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
487+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def" . to_owned( ) ) ] ) ;
488+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/abc" . to_owned( ) ) ] ) ;
489+ let fsc = builder. build ( ) ;
490+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 2 ] } ;
491+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
492+
493+ assert_eq ! ( vc, vec![ ( SourceRootId ( 2 ) , SourceRootId ( 1 ) ) ] )
494+ }
523495
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- }
496+ #[ test]
497+ fn deep_sources_with_parent_missing ( ) {
498+ let mut builder = FileSetConfigBuilder :: default ( ) ;
499+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
500+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/ghi" . to_owned( ) ) ] ) ;
501+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/abc" . to_owned( ) ) ] ) ;
502+ let fsc = builder. build ( ) ;
503+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 2 ] } ;
504+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
505+
506+ assert_eq ! ( vc, vec![ ] )
507+ }
542508
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- }
509+ #[ test]
510+ fn ancestor_can_be_parent ( ) {
511+ let mut builder = FileSetConfigBuilder :: default ( ) ;
512+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
513+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def" . to_owned( ) ) ] ) ;
514+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/ghi/jkl" . to_owned( ) ) ] ) ;
515+ let fsc = builder. build ( ) ;
516+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 2 ] } ;
517+ let vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
518+
519+ assert_eq ! ( vc, vec![ ( SourceRootId ( 2 ) , SourceRootId ( 1 ) ) ] )
520+ }
565521
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- }
522+ #[ test]
523+ fn ancestor_can_be_parent_2 ( ) {
524+ let mut builder = FileSetConfigBuilder :: default ( ) ;
525+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
526+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def" . to_owned( ) ) ] ) ;
527+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/ghi/jkl" . to_owned( ) ) ] ) ;
528+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/ghi/klm" . to_owned( ) ) ] ) ;
529+ let fsc = builder. build ( ) ;
530+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 2 , 3 ] } ;
531+ let mut vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
532+ vc. sort_by ( |x, y| x. 0 . 0 . cmp ( & y. 0 . 0 ) ) ;
533+
534+ assert_eq ! ( vc, vec![ ( SourceRootId ( 2 ) , SourceRootId ( 1 ) ) , ( SourceRootId ( 3 ) , SourceRootId ( 1 ) ) ] )
535+ }
592536
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- }
537+ #[ test]
538+ fn non_locals_are_skipped ( ) {
539+ let mut builder = FileSetConfigBuilder :: default ( ) ;
540+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
541+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def" . to_owned( ) ) ] ) ;
542+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/ghi/jkl" . to_owned( ) ) ] ) ;
543+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/klm" . to_owned( ) ) ] ) ;
544+ let fsc = builder. build ( ) ;
545+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 3 ] } ;
546+ let mut vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
547+ vc. sort_by ( |x, y| x. 0 . 0 . cmp ( & y. 0 . 0 ) ) ;
548+
549+ assert_eq ! ( vc, vec![ ( SourceRootId ( 3 ) , SourceRootId ( 1 ) ) , ] )
550+ }
618551
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- }
552+ #[ test]
553+ fn child_binds_ancestor_if_parent_nonlocal ( ) {
554+ let mut builder = FileSetConfigBuilder :: default ( ) ;
555+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/abc" . to_owned( ) ) ] ) ;
556+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def" . to_owned( ) ) ] ) ;
557+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/klm" . to_owned( ) ) ] ) ;
558+ builder. add_file_set ( vec ! [ VfsPath :: new_virtual_path( "/ROOT/def/klm/jkl" . to_owned( ) ) ] ) ;
559+ let fsc = builder. build ( ) ;
560+ let src = SourceRootConfig { fsc, local_filesets : vec ! [ 0 , 1 , 3 ] } ;
561+ let mut vc = src. source_root_parent_map ( ) . into_iter ( ) . collect :: < Vec < _ > > ( ) ;
562+ vc. sort_by ( |x, y| x. 0 . 0 . cmp ( & y. 0 . 0 ) ) ;
563+
564+ assert_eq ! ( vc, vec![ ( SourceRootId ( 3 ) , SourceRootId ( 1 ) ) , ] )
644565 }
645566}
0 commit comments