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