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