1
1
//! An algorithm to find a path to refer to a certain item.
2
2
3
+ use std:: iter;
4
+
3
5
use hir_expand:: name:: { known, AsName , Name } ;
4
6
use rustc_hash:: FxHashSet ;
5
7
use test_utils:: mark;
@@ -95,7 +97,7 @@ fn find_path_inner(
95
97
item : ItemInNs ,
96
98
from : ModuleId ,
97
99
max_len : usize ,
98
- prefixed : Option < PrefixKind > ,
100
+ mut prefixed : Option < PrefixKind > ,
99
101
) -> Option < ModPath > {
100
102
if max_len == 0 {
101
103
return None ;
@@ -114,8 +116,9 @@ fn find_path_inner(
114
116
}
115
117
116
118
// - if the item is the crate root, return `crate`
117
- let root = def_map. module_id ( def_map . root ( ) ) ;
119
+ let root = def_map. crate_root ( db ) ;
118
120
if item == ItemInNs :: Types ( ModuleDefId :: ModuleId ( root) ) && def_map. block_id ( ) . is_none ( ) {
121
+ // FIXME: the `block_id()` check should be unnecessary, but affects the result
119
122
return Some ( ModPath :: from_segments ( PathKind :: Crate , Vec :: new ( ) ) ) ;
120
123
}
121
124
@@ -165,7 +168,7 @@ fn find_path_inner(
165
168
166
169
// - otherwise, look for modules containing (reexporting) it and import it from one of those
167
170
168
- let crate_root = def_map. module_id ( def_map . root ( ) ) ;
171
+ let crate_root = def_map. crate_root ( db ) ;
169
172
let crate_attrs = db. attrs ( crate_root. into ( ) ) ;
170
173
let prefer_no_std = crate_attrs. by_key ( "no_std" ) . exists ( ) ;
171
174
let mut best_path = None ;
@@ -228,12 +231,16 @@ fn find_path_inner(
228
231
}
229
232
}
230
233
231
- if let Some ( mut prefix) = prefixed. map ( PrefixKind :: prefix) {
232
- if matches ! ( prefix, PathKind :: Crate | PathKind :: Super ( 0 ) ) && def_map. block_id ( ) . is_some ( ) {
233
- // Inner items cannot be referred to via `crate::` or `self::` paths.
234
- prefix = PathKind :: Plain ;
234
+ // If the item is declared inside a block expression, don't use a prefix, as we don't handle
235
+ // that correctly (FIXME).
236
+ if let Some ( item_module) = item. as_module_def_id ( ) . and_then ( |did| did. module ( db) ) {
237
+ if item_module. def_map ( db) . block_id ( ) . is_some ( ) && prefixed. is_some ( ) {
238
+ mark:: hit!( prefixed_in_block_expression) ;
239
+ prefixed = Some ( PrefixKind :: Plain ) ;
235
240
}
241
+ }
236
242
243
+ if let Some ( prefix) = prefixed. map ( PrefixKind :: prefix) {
237
244
best_path. or_else ( || {
238
245
scope_name. map ( |scope_name| ModPath :: from_segments ( prefix, vec ! [ scope_name] ) )
239
246
} )
@@ -285,12 +292,12 @@ fn find_local_import_locations(
285
292
let data = & def_map[ from. local_id ] ;
286
293
let mut worklist =
287
294
data. children . values ( ) . map ( |child| def_map. module_id ( * child) ) . collect :: < Vec < _ > > ( ) ;
288
- let mut parent = data. parent ;
289
- while let Some ( p) = parent {
290
- worklist. push ( def_map. module_id ( p) ) ;
291
- parent = def_map[ p] . parent ;
295
+ for ancestor in iter:: successors ( from. containing_module ( db) , |m| m. containing_module ( db) ) {
296
+ worklist. push ( ancestor) ;
292
297
}
293
298
299
+ let def_map = def_map. crate_root ( db) . def_map ( db) ;
300
+
294
301
let mut seen: FxHashSet < _ > = FxHashSet :: default ( ) ;
295
302
296
303
let mut locations = Vec :: new ( ) ;
@@ -301,7 +308,14 @@ fn find_local_import_locations(
301
308
302
309
let ext_def_map;
303
310
let data = if module. krate == from. krate {
304
- & def_map[ module. local_id ]
311
+ if module. block . is_some ( ) {
312
+ // Re-query the block's DefMap
313
+ ext_def_map = module. def_map ( db) ;
314
+ & ext_def_map[ module. local_id ]
315
+ } else {
316
+ // Reuse the root DefMap
317
+ & def_map[ module. local_id ]
318
+ }
305
319
} else {
306
320
// The crate might reexport a module defined in another crate.
307
321
ext_def_map = module. def_map ( db) ;
@@ -828,6 +842,7 @@ mod tests {
828
842
829
843
#[ test]
830
844
fn inner_items_from_inner_module ( ) {
845
+ mark:: check!( prefixed_in_block_expression) ;
831
846
check_found_path (
832
847
r#"
833
848
fn main() {
@@ -869,4 +884,24 @@ mod tests {
869
884
"super::Struct" ,
870
885
) ;
871
886
}
887
+
888
+ #[ test]
889
+ fn outer_items_with_inner_items_present ( ) {
890
+ check_found_path (
891
+ r#"
892
+ mod module {
893
+ pub struct CompleteMe;
894
+ }
895
+
896
+ fn main() {
897
+ fn inner() {}
898
+ $0
899
+ }
900
+ "# ,
901
+ "module::CompleteMe" ,
902
+ "module::CompleteMe" ,
903
+ "crate::module::CompleteMe" ,
904
+ "self::module::CompleteMe" ,
905
+ )
906
+ }
872
907
}
0 commit comments