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