@@ -13,7 +13,7 @@ use rustc_hash::FxHashSet;
13
13
use crate :: {
14
14
db:: DefDatabase ,
15
15
item_scope:: ItemInNs ,
16
- nameres:: DefMap ,
16
+ nameres:: { DefMap , ModuleData } ,
17
17
path:: { ModPath , PathKind } ,
18
18
visibility:: { Visibility , VisibilityExplicitness } ,
19
19
ImportPathConfig , ModuleDefId , ModuleId ,
@@ -161,7 +161,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
161
161
#[ tracing:: instrument( skip_all) ]
162
162
fn find_path_for_module (
163
163
ctx : & FindPathCtx < ' _ > ,
164
- visited_modules : & mut FxHashSet < ModuleId > ,
164
+ visited_modules : & mut FxHashSet < ( ItemInNs , ModuleId ) > ,
165
165
module_id : ModuleId ,
166
166
maybe_extern : bool ,
167
167
max_len : usize ,
@@ -338,7 +338,7 @@ fn is_kw_kind_relative_to_from(
338
338
#[ tracing:: instrument( skip_all) ]
339
339
fn calculate_best_path (
340
340
ctx : & FindPathCtx < ' _ > ,
341
- visited_modules : & mut FxHashSet < ModuleId > ,
341
+ visited_modules : & mut FxHashSet < ( ItemInNs , ModuleId ) > ,
342
342
item : ItemInNs ,
343
343
max_len : usize ,
344
344
best_choice : & mut Option < Choice > ,
@@ -445,28 +445,32 @@ fn calculate_best_path(
445
445
446
446
fn calculate_best_path_local (
447
447
ctx : & FindPathCtx < ' _ > ,
448
- visited_modules : & mut FxHashSet < ModuleId > ,
448
+ visited_modules : & mut FxHashSet < ( ItemInNs , ModuleId ) > ,
449
449
item : ItemInNs ,
450
450
max_len : usize ,
451
451
best_choice : & mut Option < Choice > ,
452
452
) {
453
453
// FIXME: cache the `find_local_import_locations` output?
454
- find_local_import_locations ( ctx. db , item, ctx. from , ctx. from_def_map , |name, module_id| {
455
- if !visited_modules. insert ( module_id) {
456
- return ;
457
- }
458
- // we are looking for paths of length up to best_path_len, any longer will make it be
459
- // less optimal. The -1 is due to us pushing name onto it afterwards.
460
- if let Some ( choice) = find_path_for_module (
461
- ctx,
462
- visited_modules,
463
- module_id,
464
- false ,
465
- best_choice. as_ref ( ) . map_or ( max_len, |it| it. path . len ( ) ) - 1 ,
466
- ) {
467
- Choice :: try_select ( best_choice, choice, ctx. cfg . prefer_prelude , name. clone ( ) ) ;
468
- }
469
- } ) ;
454
+ find_local_import_locations (
455
+ ctx. db ,
456
+ item,
457
+ ctx. from ,
458
+ ctx. from_def_map ,
459
+ visited_modules,
460
+ |visited_modules, name, module_id| {
461
+ // we are looking for paths of length up to best_path_len, any longer will make it be
462
+ // less optimal. The -1 is due to us pushing name onto it afterwards.
463
+ if let Some ( choice) = find_path_for_module (
464
+ ctx,
465
+ visited_modules,
466
+ module_id,
467
+ false ,
468
+ best_choice. as_ref ( ) . map_or ( max_len, |it| it. path . len ( ) ) - 1 ,
469
+ ) {
470
+ Choice :: try_select ( best_choice, choice, ctx. cfg . prefer_prelude , name. clone ( ) ) ;
471
+ }
472
+ } ,
473
+ ) ;
470
474
}
471
475
472
476
struct Choice {
@@ -551,7 +555,8 @@ fn find_local_import_locations(
551
555
item : ItemInNs ,
552
556
from : ModuleId ,
553
557
def_map : & DefMap ,
554
- mut cb : impl FnMut ( & Name , ModuleId ) ,
558
+ visited_modules : & mut FxHashSet < ( ItemInNs , ModuleId ) > ,
559
+ mut cb : impl FnMut ( & mut FxHashSet < ( ItemInNs , ModuleId ) > , & Name , ModuleId ) ,
555
560
) {
556
561
let _p = tracing:: info_span!( "find_local_import_locations" ) . entered ( ) ;
557
562
@@ -564,32 +569,29 @@ fn find_local_import_locations(
564
569
let mut worklist = def_map[ from. local_id ]
565
570
. children
566
571
. values ( )
567
- . map ( |child| def_map. module_id ( * child) )
568
- // FIXME: do we need to traverse out of block expressions here?
572
+ . map ( |& child| def_map. module_id ( child) )
569
573
. chain ( iter:: successors ( from. containing_module ( db) , |m| m. containing_module ( db) ) )
574
+ . zip ( iter:: repeat ( false ) )
570
575
. collect :: < Vec < _ > > ( ) ;
571
- let mut seen: FxHashSet < _ > = FxHashSet :: default ( ) ;
572
576
573
577
let def_map = def_map. crate_root ( ) . def_map ( db) ;
574
-
575
- while let Some ( module) = worklist. pop ( ) {
576
- if !seen. insert ( module) {
577
- continue ; // already processed this module
578
+ let mut block_def_map;
579
+ let mut cursor = 0 ;
580
+
581
+ while let Some ( & mut ( module, ref mut processed) ) = worklist. get_mut ( cursor) {
582
+ cursor += 1 ;
583
+ if !visited_modules. insert ( ( item, module) ) {
584
+ // already processed this module
585
+ continue ;
578
586
}
579
- let ext_def_map;
580
- let data = if module. krate == from. krate {
581
- if module. block . is_some ( ) {
582
- // Re-query the block's DefMap
583
- ext_def_map = module. def_map ( db) ;
584
- & ext_def_map[ module. local_id ]
585
- } else {
586
- // Reuse the root DefMap
587
- & def_map[ module. local_id ]
588
- }
587
+ * processed = true ;
588
+ let data = if module. block . is_some ( ) {
589
+ // Re-query the block's DefMap
590
+ block_def_map = module. def_map ( db) ;
591
+ & block_def_map[ module. local_id ]
589
592
} else {
590
- // The crate might reexport a module defined in another crate.
591
- ext_def_map = module. def_map ( db) ;
592
- & ext_def_map[ module. local_id ]
593
+ // Reuse the root DefMap
594
+ & def_map[ module. local_id ]
593
595
} ;
594
596
595
597
if let Some ( ( name, vis, declared) ) = data. scope . name_of ( item) {
@@ -612,18 +614,30 @@ fn find_local_import_locations(
612
614
// the item and we're a submodule of it, so can we.
613
615
// Also this keeps the cached data smaller.
614
616
if declared || is_pub_or_explicit {
615
- cb ( name, module) ;
617
+ cb ( visited_modules , name, module) ;
616
618
}
617
619
}
618
620
}
619
621
620
622
// Descend into all modules visible from `from`.
621
623
for ( module, vis) in data. scope . modules_in_scope ( ) {
624
+ if module. krate != from. krate {
625
+ // We don't need to look at modules from other crates as our item has to be in the
626
+ // current crate
627
+ continue ;
628
+ }
629
+ if visited_modules. contains ( & ( item, module) ) {
630
+ continue ;
631
+ }
632
+
622
633
if vis. is_visible_from ( db, from) {
623
- worklist. push ( module) ;
634
+ worklist. push ( ( module, false ) ) ;
624
635
}
625
636
}
626
637
}
638
+ worklist. into_iter ( ) . filter ( |& ( _, processed) | processed) . for_each ( |( module, _) | {
639
+ visited_modules. remove ( & ( item, module) ) ;
640
+ } ) ;
627
641
}
628
642
629
643
#[ cfg( test) ]
@@ -1591,8 +1605,6 @@ fn main() {
1591
1605
1592
1606
#[ test]
1593
1607
fn from_inside_module ( ) {
1594
- // This worked correctly, but the test suite logic was broken.
1595
- cov_mark:: check!( submodule_in_testdb) ;
1596
1608
check_found_path (
1597
1609
r#"
1598
1610
mod baz {
@@ -1617,6 +1629,35 @@ mod bar {
1617
1629
)
1618
1630
}
1619
1631
1632
+ #[ test]
1633
+ fn from_inside_module2 ( ) {
1634
+ check_found_path (
1635
+ r#"
1636
+ mod qux {
1637
+ pub mod baz {
1638
+ pub struct Foo {}
1639
+ }
1640
+
1641
+ mod bar {
1642
+ fn bar() {
1643
+ $0;
1644
+ }
1645
+ }
1646
+ }
1647
+
1648
+ "# ,
1649
+ "crate::qux::baz::Foo" ,
1650
+ expect ! [ [ r#"
1651
+ Plain (imports ✔): super::baz::Foo
1652
+ Plain (imports ✖): super::baz::Foo
1653
+ ByCrate(imports ✔): crate::qux::baz::Foo
1654
+ ByCrate(imports ✖): crate::qux::baz::Foo
1655
+ BySelf (imports ✔): super::baz::Foo
1656
+ BySelf (imports ✖): super::baz::Foo
1657
+ "# ] ] ,
1658
+ )
1659
+ }
1660
+
1620
1661
#[ test]
1621
1662
fn from_inside_module_with_inner_items ( ) {
1622
1663
check_found_path (
0 commit comments