]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/find_path.rs
Merge #7994
[rust.git] / crates / hir_def / src / find_path.rs
1 //! An algorithm to find a path to refer to a certain item.
2
3 use std::iter;
4
5 use hir_expand::name::{known, AsName, Name};
6 use rustc_hash::FxHashSet;
7
8 use crate::nameres::DefMap;
9 use crate::{
10     db::DefDatabase,
11     item_scope::ItemInNs,
12     path::{ModPath, PathKind},
13     visibility::Visibility,
14     ModuleDefId, ModuleId,
15 };
16
17 /// Find a path that can be used to refer to a certain item. This can depend on
18 /// *from where* you're referring to the item, hence the `from` parameter.
19 pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
20     let _p = profile::span("find_path");
21     find_path_inner(db, item, from, MAX_PATH_LEN, None)
22 }
23
24 pub fn find_path_prefixed(
25     db: &dyn DefDatabase,
26     item: ItemInNs,
27     from: ModuleId,
28     prefix_kind: PrefixKind,
29 ) -> Option<ModPath> {
30     let _p = profile::span("find_path_prefixed");
31     find_path_inner(db, item, from, MAX_PATH_LEN, Some(prefix_kind))
32 }
33
34 const MAX_PATH_LEN: usize = 15;
35
36 impl ModPath {
37     fn starts_with_std(&self) -> bool {
38         self.segments().first() == Some(&known::std)
39     }
40
41     // When std library is present, paths starting with `std::`
42     // should be preferred over paths starting with `core::` and `alloc::`
43     fn can_start_with_std(&self) -> bool {
44         let first_segment = self.segments().first();
45         first_segment == Some(&known::alloc) || first_segment == Some(&known::core)
46     }
47 }
48
49 fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
50     if item == ItemInNs::Types(from.into()) {
51         // - if the item is the module we're in, use `self`
52         Some(ModPath::from_segments(PathKind::Super(0), Vec::new()))
53     } else if let Some(parent_id) = def_map[from.local_id].parent {
54         // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
55         let parent_id = def_map.module_id(parent_id);
56         if item == ItemInNs::Types(ModuleDefId::ModuleId(parent_id)) {
57             Some(ModPath::from_segments(PathKind::Super(1), Vec::new()))
58         } else {
59             None
60         }
61     } else {
62         None
63     }
64 }
65
66 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
67 pub enum PrefixKind {
68     /// Causes paths to always start with either `self`, `super`, `crate` or a crate-name.
69     /// This is the same as plain, just that paths will start with `self` iprepended f the path
70     /// starts with an identifier that is not a crate.
71     BySelf,
72     /// Causes paths to ignore imports in the local module.
73     Plain,
74     /// Causes paths to start with `crate` where applicable, effectively forcing paths to be absolute.
75     ByCrate,
76 }
77
78 impl PrefixKind {
79     #[inline]
80     fn prefix(self) -> PathKind {
81         match self {
82             PrefixKind::BySelf => PathKind::Super(0),
83             PrefixKind::Plain => PathKind::Plain,
84             PrefixKind::ByCrate => PathKind::Crate,
85         }
86     }
87
88     #[inline]
89     fn is_absolute(&self) -> bool {
90         self == &PrefixKind::ByCrate
91     }
92 }
93
94 fn find_path_inner(
95     db: &dyn DefDatabase,
96     item: ItemInNs,
97     from: ModuleId,
98     max_len: usize,
99     mut prefixed: Option<PrefixKind>,
100 ) -> Option<ModPath> {
101     if max_len == 0 {
102         return None;
103     }
104
105     // Base cases:
106
107     // - if the item is already in scope, return the name under which it is
108     let def_map = from.def_map(db);
109     let scope_name = def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
110         def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone())
111     });
112     if prefixed.is_none() && scope_name.is_some() {
113         return scope_name
114             .map(|scope_name| ModPath::from_segments(PathKind::Plain, vec![scope_name]));
115     }
116
117     // - if the item is the crate root, return `crate`
118     let root = def_map.crate_root(db);
119     if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() {
120         // FIXME: the `block_id()` check should be unnecessary, but affects the result
121         return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
122     }
123
124     if prefixed.filter(PrefixKind::is_absolute).is_none() {
125         if let modpath @ Some(_) = check_self_super(&def_map, item, from) {
126             return modpath;
127         }
128     }
129
130     // - if the item is the crate root of a dependency crate, return the name from the extern prelude
131     for (name, def_id) in def_map.extern_prelude() {
132         if item == ItemInNs::Types(*def_id) {
133             let name = scope_name.unwrap_or_else(|| name.clone());
134             return Some(ModPath::from_segments(PathKind::Plain, vec![name]));
135         }
136     }
137
138     // - if the item is in the prelude, return the name from there
139     if let Some(prelude_module) = def_map.prelude() {
140         let prelude_def_map = prelude_module.def_map(db);
141         let prelude_scope: &crate::item_scope::ItemScope =
142             &prelude_def_map[prelude_module.local_id].scope;
143         if let Some((name, vis)) = prelude_scope.name_of(item) {
144             if vis.is_visible_from(db, from) {
145                 return Some(ModPath::from_segments(PathKind::Plain, vec![name.clone()]));
146             }
147         }
148     }
149
150     // - if the item is a builtin, it's in scope
151     if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
152         return Some(ModPath::from_segments(PathKind::Plain, vec![builtin.as_name()]));
153     }
154
155     // Recursive case:
156     // - if the item is an enum variant, refer to it via the enum
157     if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
158         if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) {
159             let data = db.enum_data(variant.parent);
160             path.push_segment(data.variants[variant.local_id].name.clone());
161             return Some(path);
162         }
163         // If this doesn't work, it seems we have no way of referring to the
164         // enum; that's very weird, but there might still be a reexport of the
165         // variant somewhere
166     }
167
168     // - otherwise, look for modules containing (reexporting) it and import it from one of those
169
170     let crate_root = def_map.crate_root(db);
171     let crate_attrs = db.attrs(crate_root.into());
172     let prefer_no_std = crate_attrs.by_key("no_std").exists();
173     let mut best_path = None;
174     let mut best_path_len = max_len;
175
176     if item.krate(db) == Some(from.krate) {
177         // Item was defined in the same crate that wants to import it. It cannot be found in any
178         // dependency in this case.
179
180         let local_imports = find_local_import_locations(db, item, from);
181         for (module_id, name) in local_imports {
182             if let Some(mut path) = find_path_inner(
183                 db,
184                 ItemInNs::Types(ModuleDefId::ModuleId(module_id)),
185                 from,
186                 best_path_len - 1,
187                 prefixed,
188             ) {
189                 path.push_segment(name);
190
191                 let new_path = if let Some(best_path) = best_path {
192                     select_best_path(best_path, path, prefer_no_std)
193                 } else {
194                     path
195                 };
196                 best_path_len = new_path.len();
197                 best_path = Some(new_path);
198             }
199         }
200     } else {
201         // Item was defined in some upstream crate. This means that it must be exported from one,
202         // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
203         // that wants to import it here, but we always prefer to use the external path here.
204
205         let crate_graph = db.crate_graph();
206         let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
207             let import_map = db.import_map(dep.crate_id);
208             import_map.import_info_for(item).and_then(|info| {
209                 // Determine best path for containing module and append last segment from `info`.
210                 let mut path = find_path_inner(
211                     db,
212                     ItemInNs::Types(ModuleDefId::ModuleId(info.container)),
213                     from,
214                     best_path_len - 1,
215                     prefixed,
216                 )?;
217                 cov_mark::hit!(partially_imported);
218                 path.push_segment(info.path.segments.last().unwrap().clone());
219                 Some(path)
220             })
221         });
222
223         for path in extern_paths {
224             let new_path = if let Some(best_path) = best_path {
225                 select_best_path(best_path, path, prefer_no_std)
226             } else {
227                 path
228             };
229             best_path = Some(new_path);
230         }
231     }
232
233     // If the item is declared inside a block expression, don't use a prefix, as we don't handle
234     // that correctly (FIXME).
235     if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) {
236         if item_module.def_map(db).block_id().is_some() && prefixed.is_some() {
237             cov_mark::hit!(prefixed_in_block_expression);
238             prefixed = Some(PrefixKind::Plain);
239         }
240     }
241
242     if let Some(prefix) = prefixed.map(PrefixKind::prefix) {
243         best_path.or_else(|| {
244             scope_name.map(|scope_name| ModPath::from_segments(prefix, vec![scope_name]))
245         })
246     } else {
247         best_path
248     }
249 }
250
251 fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath {
252     if old_path.starts_with_std() && new_path.can_start_with_std() {
253         if prefer_no_std {
254             cov_mark::hit!(prefer_no_std_paths);
255             new_path
256         } else {
257             cov_mark::hit!(prefer_std_paths);
258             old_path
259         }
260     } else if new_path.starts_with_std() && old_path.can_start_with_std() {
261         if prefer_no_std {
262             cov_mark::hit!(prefer_no_std_paths);
263             old_path
264         } else {
265             cov_mark::hit!(prefer_std_paths);
266             new_path
267         }
268     } else if new_path.len() < old_path.len() {
269         new_path
270     } else {
271         old_path
272     }
273 }
274
275 /// Finds locations in `from.krate` from which `item` can be imported by `from`.
276 fn find_local_import_locations(
277     db: &dyn DefDatabase,
278     item: ItemInNs,
279     from: ModuleId,
280 ) -> Vec<(ModuleId, Name)> {
281     let _p = profile::span("find_local_import_locations");
282
283     // `from` can import anything below `from` with visibility of at least `from`, and anything
284     // above `from` with any visibility. That means we do not need to descend into private siblings
285     // of `from` (and similar).
286
287     let def_map = from.def_map(db);
288
289     // Compute the initial worklist. We start with all direct child modules of `from` as well as all
290     // of its (recursive) parent modules.
291     let data = &def_map[from.local_id];
292     let mut worklist =
293         data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
294     for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) {
295         worklist.push(ancestor);
296     }
297
298     let def_map = def_map.crate_root(db).def_map(db);
299
300     let mut seen: FxHashSet<_> = FxHashSet::default();
301
302     let mut locations = Vec::new();
303     while let Some(module) = worklist.pop() {
304         if !seen.insert(module) {
305             continue; // already processed this module
306         }
307
308         let ext_def_map;
309         let data = if module.krate == from.krate {
310             if module.block.is_some() {
311                 // Re-query the block's DefMap
312                 ext_def_map = module.def_map(db);
313                 &ext_def_map[module.local_id]
314             } else {
315                 // Reuse the root DefMap
316                 &def_map[module.local_id]
317             }
318         } else {
319             // The crate might reexport a module defined in another crate.
320             ext_def_map = module.def_map(db);
321             &ext_def_map[module.local_id]
322         };
323
324         if let Some((name, vis)) = data.scope.name_of(item) {
325             if vis.is_visible_from(db, from) {
326                 let is_private = if let Visibility::Module(private_to) = vis {
327                     private_to.local_id == module.local_id
328                 } else {
329                     false
330                 };
331                 let is_original_def = if let Some(module_def_id) = item.as_module_def_id() {
332                     data.scope.declarations().any(|it| it == module_def_id)
333                 } else {
334                     false
335                 };
336
337                 // Ignore private imports. these could be used if we are
338                 // in a submodule of this module, but that's usually not
339                 // what the user wants; and if this module can import
340                 // the item and we're a submodule of it, so can we.
341                 // Also this keeps the cached data smaller.
342                 if !is_private || is_original_def {
343                     locations.push((module, name.clone()));
344                 }
345             }
346         }
347
348         // Descend into all modules visible from `from`.
349         for (_, per_ns) in data.scope.entries() {
350             if let Some((ModuleDefId::ModuleId(module), vis)) = per_ns.take_types_vis() {
351                 if vis.is_visible_from(db, from) {
352                     worklist.push(module);
353                 }
354             }
355         }
356     }
357
358     locations
359 }
360
361 #[cfg(test)]
362 mod tests {
363     use base_db::fixture::WithFixture;
364     use hir_expand::hygiene::Hygiene;
365     use syntax::ast::AstNode;
366
367     use crate::test_db::TestDB;
368
369     use super::*;
370
371     /// `code` needs to contain a cursor marker; checks that `find_path` for the
372     /// item the `path` refers to returns that same path when called from the
373     /// module the cursor is in.
374     fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKind>) {
375         let (db, pos) = TestDB::with_position(ra_fixture);
376         let module = db.module_at_position(pos);
377         let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path));
378         let ast_path =
379             parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
380         let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap();
381
382         let def_map = module.def_map(&db);
383         let resolved = def_map
384             .resolve_path(
385                 &db,
386                 module.local_id,
387                 &mod_path,
388                 crate::item_scope::BuiltinShadowMode::Module,
389             )
390             .0
391             .take_types()
392             .unwrap();
393
394         let found_path =
395             find_path_inner(&db, ItemInNs::Types(resolved), module, MAX_PATH_LEN, prefix_kind);
396         assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
397     }
398
399     fn check_found_path(
400         ra_fixture: &str,
401         unprefixed: &str,
402         prefixed: &str,
403         absolute: &str,
404         self_prefixed: &str,
405     ) {
406         check_found_path_(ra_fixture, unprefixed, None);
407         check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain));
408         check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate));
409         check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf));
410     }
411
412     #[test]
413     fn same_module() {
414         let code = r#"
415             //- /main.rs
416             struct S;
417             $0
418         "#;
419         check_found_path(code, "S", "S", "crate::S", "self::S");
420     }
421
422     #[test]
423     fn enum_variant() {
424         let code = r#"
425             //- /main.rs
426             enum E { A }
427             $0
428         "#;
429         check_found_path(code, "E::A", "E::A", "E::A", "E::A");
430     }
431
432     #[test]
433     fn sub_module() {
434         let code = r#"
435             //- /main.rs
436             mod foo {
437                 pub struct S;
438             }
439             $0
440         "#;
441         check_found_path(code, "foo::S", "foo::S", "crate::foo::S", "self::foo::S");
442     }
443
444     #[test]
445     fn super_module() {
446         let code = r#"
447             //- /main.rs
448             mod foo;
449             //- /foo.rs
450             mod bar;
451             struct S;
452             //- /foo/bar.rs
453             $0
454         "#;
455         check_found_path(code, "super::S", "super::S", "crate::foo::S", "super::S");
456     }
457
458     #[test]
459     fn self_module() {
460         let code = r#"
461             //- /main.rs
462             mod foo;
463             //- /foo.rs
464             $0
465         "#;
466         check_found_path(code, "self", "self", "crate::foo", "self");
467     }
468
469     #[test]
470     fn crate_root() {
471         let code = r#"
472             //- /main.rs
473             mod foo;
474             //- /foo.rs
475             $0
476         "#;
477         check_found_path(code, "crate", "crate", "crate", "crate");
478     }
479
480     #[test]
481     fn same_crate() {
482         let code = r#"
483             //- /main.rs
484             mod foo;
485             struct S;
486             //- /foo.rs
487             $0
488         "#;
489         check_found_path(code, "crate::S", "crate::S", "crate::S", "crate::S");
490     }
491
492     #[test]
493     fn different_crate() {
494         let code = r#"
495             //- /main.rs crate:main deps:std
496             $0
497             //- /std.rs crate:std
498             pub struct S;
499         "#;
500         check_found_path(code, "std::S", "std::S", "std::S", "std::S");
501     }
502
503     #[test]
504     fn different_crate_renamed() {
505         let code = r#"
506             //- /main.rs crate:main deps:std
507             extern crate std as std_renamed;
508             $0
509             //- /std.rs crate:std
510             pub struct S;
511         "#;
512         check_found_path(
513             code,
514             "std_renamed::S",
515             "std_renamed::S",
516             "std_renamed::S",
517             "std_renamed::S",
518         );
519     }
520
521     #[test]
522     fn partially_imported() {
523         cov_mark::check!(partially_imported);
524         // Tests that short paths are used even for external items, when parts of the path are
525         // already in scope.
526         let code = r#"
527             //- /main.rs crate:main deps:syntax
528
529             use syntax::ast;
530             $0
531
532             //- /lib.rs crate:syntax
533             pub mod ast {
534                 pub enum ModuleItem {
535                     A, B, C,
536                 }
537             }
538         "#;
539         check_found_path(
540             code,
541             "ast::ModuleItem",
542             "syntax::ast::ModuleItem",
543             "syntax::ast::ModuleItem",
544             "syntax::ast::ModuleItem",
545         );
546
547         let code = r#"
548             //- /main.rs crate:main deps:syntax
549
550             $0
551
552             //- /lib.rs crate:syntax
553             pub mod ast {
554                 pub enum ModuleItem {
555                     A, B, C,
556                 }
557             }
558         "#;
559         check_found_path(
560             code,
561             "syntax::ast::ModuleItem",
562             "syntax::ast::ModuleItem",
563             "syntax::ast::ModuleItem",
564             "syntax::ast::ModuleItem",
565         );
566     }
567
568     #[test]
569     fn same_crate_reexport() {
570         let code = r#"
571             //- /main.rs
572             mod bar {
573                 mod foo { pub(super) struct S; }
574                 pub(crate) use foo::*;
575             }
576             $0
577         "#;
578         check_found_path(code, "bar::S", "bar::S", "crate::bar::S", "self::bar::S");
579     }
580
581     #[test]
582     fn same_crate_reexport_rename() {
583         let code = r#"
584             //- /main.rs
585             mod bar {
586                 mod foo { pub(super) struct S; }
587                 pub(crate) use foo::S as U;
588             }
589             $0
590         "#;
591         check_found_path(code, "bar::U", "bar::U", "crate::bar::U", "self::bar::U");
592     }
593
594     #[test]
595     fn different_crate_reexport() {
596         let code = r#"
597             //- /main.rs crate:main deps:std
598             $0
599             //- /std.rs crate:std deps:core
600             pub use core::S;
601             //- /core.rs crate:core
602             pub struct S;
603         "#;
604         check_found_path(code, "std::S", "std::S", "std::S", "std::S");
605     }
606
607     #[test]
608     fn prelude() {
609         let code = r#"
610             //- /main.rs crate:main deps:std
611             $0
612             //- /std.rs crate:std
613             pub mod prelude { pub struct S; }
614             #[prelude_import]
615             pub use prelude::*;
616         "#;
617         check_found_path(code, "S", "S", "S", "S");
618     }
619
620     #[test]
621     fn enum_variant_from_prelude() {
622         let code = r#"
623             //- /main.rs crate:main deps:std
624             $0
625             //- /std.rs crate:std
626             pub mod prelude {
627                 pub enum Option<T> { Some(T), None }
628                 pub use Option::*;
629             }
630             #[prelude_import]
631             pub use prelude::*;
632         "#;
633         check_found_path(code, "None", "None", "None", "None");
634         check_found_path(code, "Some", "Some", "Some", "Some");
635     }
636
637     #[test]
638     fn shortest_path() {
639         let code = r#"
640             //- /main.rs
641             pub mod foo;
642             pub mod baz;
643             struct S;
644             $0
645             //- /foo.rs
646             pub mod bar { pub struct S; }
647             //- /baz.rs
648             pub use crate::foo::bar::S;
649         "#;
650         check_found_path(code, "baz::S", "baz::S", "crate::baz::S", "self::baz::S");
651     }
652
653     #[test]
654     fn discount_private_imports() {
655         let code = r#"
656             //- /main.rs
657             mod foo;
658             pub mod bar { pub struct S; }
659             use bar::S;
660             //- /foo.rs
661             $0
662         "#;
663         // crate::S would be shorter, but using private imports seems wrong
664         check_found_path(code, "crate::bar::S", "crate::bar::S", "crate::bar::S", "crate::bar::S");
665     }
666
667     #[test]
668     fn import_cycle() {
669         let code = r#"
670             //- /main.rs
671             pub mod foo;
672             pub mod bar;
673             pub mod baz;
674             //- /bar.rs
675             $0
676             //- /foo.rs
677             pub use super::baz;
678             pub struct S;
679             //- /baz.rs
680             pub use super::foo;
681         "#;
682         check_found_path(code, "crate::foo::S", "crate::foo::S", "crate::foo::S", "crate::foo::S");
683     }
684
685     #[test]
686     fn prefer_std_paths_over_alloc() {
687         cov_mark::check!(prefer_std_paths);
688         let code = r#"
689         //- /main.rs crate:main deps:alloc,std
690         $0
691
692         //- /std.rs crate:std deps:alloc
693         pub mod sync {
694             pub use alloc::sync::Arc;
695         }
696
697         //- /zzz.rs crate:alloc
698         pub mod sync {
699             pub struct Arc;
700         }
701         "#;
702         check_found_path(
703             code,
704             "std::sync::Arc",
705             "std::sync::Arc",
706             "std::sync::Arc",
707             "std::sync::Arc",
708         );
709     }
710
711     #[test]
712     fn prefer_core_paths_over_std() {
713         cov_mark::check!(prefer_no_std_paths);
714         let code = r#"
715         //- /main.rs crate:main deps:core,std
716         #![no_std]
717
718         $0
719
720         //- /std.rs crate:std deps:core
721
722         pub mod fmt {
723             pub use core::fmt::Error;
724         }
725
726         //- /zzz.rs crate:core
727
728         pub mod fmt {
729             pub struct Error;
730         }
731         "#;
732         check_found_path(
733             code,
734             "core::fmt::Error",
735             "core::fmt::Error",
736             "core::fmt::Error",
737             "core::fmt::Error",
738         );
739     }
740
741     #[test]
742     fn prefer_alloc_paths_over_std() {
743         let code = r#"
744         //- /main.rs crate:main deps:alloc,std
745         #![no_std]
746
747         $0
748
749         //- /std.rs crate:std deps:alloc
750
751         pub mod sync {
752             pub use alloc::sync::Arc;
753         }
754
755         //- /zzz.rs crate:alloc
756
757         pub mod sync {
758             pub struct Arc;
759         }
760         "#;
761         check_found_path(
762             code,
763             "alloc::sync::Arc",
764             "alloc::sync::Arc",
765             "alloc::sync::Arc",
766             "alloc::sync::Arc",
767         );
768     }
769
770     #[test]
771     fn prefer_shorter_paths_if_not_alloc() {
772         let code = r#"
773         //- /main.rs crate:main deps:megaalloc,std
774         $0
775
776         //- /std.rs crate:std deps:megaalloc
777         pub mod sync {
778             pub use megaalloc::sync::Arc;
779         }
780
781         //- /zzz.rs crate:megaalloc
782         pub struct Arc;
783         "#;
784         check_found_path(
785             code,
786             "megaalloc::Arc",
787             "megaalloc::Arc",
788             "megaalloc::Arc",
789             "megaalloc::Arc",
790         );
791     }
792
793     #[test]
794     fn builtins_are_in_scope() {
795         let code = r#"
796         //- /main.rs
797         $0
798
799         pub mod primitive {
800             pub use u8;
801         }
802         "#;
803         check_found_path(code, "u8", "u8", "u8", "u8");
804         check_found_path(code, "u16", "u16", "u16", "u16");
805     }
806
807     #[test]
808     fn inner_items() {
809         check_found_path(
810             r#"
811             fn main() {
812                 struct Inner {}
813                 $0
814             }
815         "#,
816             "Inner",
817             "Inner",
818             "Inner",
819             "Inner",
820         );
821     }
822
823     #[test]
824     fn inner_items_from_outer_scope() {
825         check_found_path(
826             r#"
827             fn main() {
828                 struct Struct {}
829                 {
830                     $0
831                 }
832             }
833         "#,
834             "Struct",
835             "Struct",
836             "Struct",
837             "Struct",
838         );
839     }
840
841     #[test]
842     fn inner_items_from_inner_module() {
843         cov_mark::check!(prefixed_in_block_expression);
844         check_found_path(
845             r#"
846             fn main() {
847                 mod module {
848                     struct Struct {}
849                 }
850                 {
851                     $0
852                 }
853             }
854         "#,
855             "module::Struct",
856             "module::Struct",
857             "module::Struct",
858             "module::Struct",
859         );
860     }
861
862     #[test]
863     fn outer_items_with_inner_items_present() {
864         check_found_path(
865             r#"
866             mod module {
867                 pub struct CompleteMe;
868             }
869
870             fn main() {
871                 fn inner() {}
872                 $0
873             }
874             "#,
875             "module::CompleteMe",
876             "module::CompleteMe",
877             "crate::module::CompleteMe",
878             "self::module::CompleteMe",
879         )
880     }
881 }