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