1use std::{cell::Cell, cmp::Ordering, iter};
4
5use base_db::{Crate, CrateOrigin, LangCrateOrigin, SourceDatabase};
6use hir_expand::{
7 Lookup,
8 mod_path::{ModPath, PathKind},
9 name::{AsName, Name},
10};
11use intern::sym;
12use rustc_hash::FxHashSet;
13
14use crate::{
15 ModuleDefId, ModuleIdLt,
16 attrs::crate_supports_no_std,
17 import_map::ImportMap,
18 item_scope::ItemInNs,
19 nameres::DefMap,
20 visibility::{Visibility, VisibilityExplicitness},
21};
22
23#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
24pub struct FindPathConfig {
25 pub prefer_no_std: bool,
28 pub prefer_prelude: bool,
30 pub prefer_absolute: bool,
32 pub allow_unstable: bool,
35}
36
37pub fn find_path(
40 db: &dyn SourceDatabase,
41 item: ItemInNs,
42 from: ModuleIdLt<'_>,
43 mut prefix_kind: PrefixKind,
44 ignore_local_imports: bool,
45 mut cfg: FindPathConfig,
46) -> Option<ModPath> {
47 let _p = tracing::info_span!("find_path").entered();
48
49 if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
51 return Some(ModPath::from_segments(PathKind::Plain, iter::once(builtin.as_name())));
52 }
53
54 let item_module = item.module(db)?;
57 if item_module.block(db).is_some() {
58 prefix_kind = PrefixKind::Plain;
59 }
60
61 let from_def_map = from.def_map(db);
62
63 let from_crate = from.krate(db);
64 cfg.prefer_no_std =
65 cfg.prefer_no_std || from_def_map.is_no_std() || crate_supports_no_std(db, from_crate);
66
67 find_path_inner(
68 &FindPathCtx {
69 db,
70 prefix: prefix_kind,
71 cfg,
72 ignore_local_imports,
73 is_std_item: item_module.krate(db).data(db).origin.is_lang(),
74 from,
75 from_crate,
76 crate_root: from_def_map.crate_root(db),
77 from_def_map,
78 fuel: Cell::new(FIND_PATH_FUEL),
79 },
80 item,
81 MAX_PATH_LEN,
82 )
83}
84
85#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
86enum Stability {
87 Unstable,
88 Stable,
89}
90use Stability::*;
91
92const MAX_PATH_LEN: usize = 15;
93const FIND_PATH_FUEL: usize = 10000;
94
95#[derive(Copy, Clone, Debug, PartialEq, Eq)]
96pub enum PrefixKind {
97 BySelf,
101 Plain,
103 ByCrate,
105}
106
107impl PrefixKind {
108 #[inline]
109 fn path_kind(self) -> PathKind {
110 match self {
111 PrefixKind::BySelf => PathKind::SELF,
112 PrefixKind::Plain => PathKind::Plain,
113 PrefixKind::ByCrate => PathKind::Crate,
114 }
115 }
116}
117
118struct FindPathCtx<'db> {
119 db: &'db dyn SourceDatabase,
120 prefix: PrefixKind,
121 cfg: FindPathConfig,
122 ignore_local_imports: bool,
123 is_std_item: bool,
124 from: ModuleIdLt<'db>,
125 from_crate: Crate,
126 crate_root: ModuleIdLt<'db>,
127 from_def_map: &'db DefMap,
128 fuel: Cell<usize>,
129}
130
131fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option<ModPath> {
133 if !ctx.is_std_item
135 && let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item
136 {
137 return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len)
138 .map(|choice| choice.path);
139 }
140
141 let may_be_in_scope = match ctx.prefix {
142 PrefixKind::Plain | PrefixKind::BySelf => true,
143 PrefixKind::ByCrate => ctx.crate_root == ctx.from,
144 };
145 if may_be_in_scope {
146 let scope_name =
148 find_in_scope(ctx.db, ctx.from_def_map, ctx.from, item, ctx.ignore_local_imports);
149 if let Some(scope_name) = scope_name {
150 return Some(ModPath::from_segments(ctx.prefix.path_kind(), iter::once(scope_name)));
151 }
152 }
153
154 if let Some(value) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) {
156 return Some(value.path);
157 }
158
159 if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
160 let loc = variant.lookup(ctx.db);
162 if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(loc.parent.into()), max_len) {
163 path.push_segment(loc.name.clone());
164 return Some(path);
165 }
166 }
170
171 let mut best_choice = None;
172 calculate_best_path(ctx, &mut FxHashSet::default(), item, max_len, &mut best_choice);
173 best_choice.map(|choice| choice.path)
174}
175
176#[tracing::instrument(skip_all)]
177fn find_path_for_module<'db>(
178 ctx: &'db FindPathCtx<'db>,
179 visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
180 module_id: ModuleIdLt<'db>,
181 maybe_extern: bool,
182 max_len: usize,
183) -> Option<Choice> {
184 if max_len == 0 {
185 return None;
187 }
188 let module_crate_root = module_id.def_map(ctx.db).crate_root(ctx.db);
189 if module_crate_root == module_id {
190 if !maybe_extern || module_crate_root == ctx.crate_root {
191 return Some(Choice {
193 path: ModPath::from_segments(PathKind::Crate, None),
194 path_text_len: 5,
195 stability: Stable,
196 has_prelude_segment: false,
197 });
198 }
199 let root_local_def_map = ctx.crate_root.local_def_map(ctx.db).1;
202 for (name, (def_id, _extern_crate)) in root_local_def_map.extern_prelude().rev() {
204 if module_crate_root != def_id {
205 continue;
206 }
207 let name_already_occupied_in_type_ns = ctx
208 .from_def_map
209 .with_ancestor_maps(ctx.db, ctx.from, &mut |def_map, local_id| {
210 def_map[local_id]
211 .scope
212 .type_(name)
213 .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id))
214 })
215 .is_some();
216 let kind = if name_already_occupied_in_type_ns {
217 cov_mark::hit!(ambiguous_crate_start);
218 PathKind::Abs
219 } else if ctx.cfg.prefer_absolute {
220 PathKind::Abs
221 } else {
222 PathKind::Plain
223 };
224 return Some(Choice::new(kind, name.clone(), Stable));
225 }
226 }
227
228 let may_be_in_scope = match ctx.prefix {
229 PrefixKind::Plain | PrefixKind::BySelf => true,
230 PrefixKind::ByCrate => ctx.crate_root == ctx.from,
231 };
232 if may_be_in_scope {
233 let scope_name = find_in_scope(
234 ctx.db,
235 ctx.from_def_map,
236 ctx.from,
237 ItemInNs::Types(unsafe { module_id.to_static() }.into()),
238 ctx.ignore_local_imports,
239 );
240 if let Some(scope_name) = scope_name {
241 return Some(Choice::new(ctx.prefix.path_kind(), scope_name, Stable));
243 }
244 }
245
246 if let Some(kind) = is_kw_kind_relative_to_from(ctx.db, ctx.from_def_map, module_id, ctx.from)
248 && (ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate)
249 {
250 return Some(Choice {
251 path: ModPath::from_segments(kind, None),
252 path_text_len: path_kind_len(kind),
253 stability: Stable,
254 has_prelude_segment: false,
255 });
256 }
257
258 let item = ItemInNs::Types(unsafe { module_id.to_static() }.into());
260 if let Some(choice) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) {
261 return Some(choice);
262 }
263 let mut best_choice = None;
264 if maybe_extern {
265 calculate_best_path(ctx, visited_modules, item, max_len, &mut best_choice);
266 } else {
267 calculate_best_path_local(ctx, visited_modules, item, max_len, &mut best_choice);
268 }
269 best_choice
270}
271
272fn find_in_scope<'db>(
273 db: &'db dyn SourceDatabase,
274 def_map: &DefMap,
275 from: ModuleIdLt<'db>,
276 item: ItemInNs,
277 ignore_local_imports: bool,
278) -> Option<Name> {
279 def_map.with_ancestor_maps(db, from, &mut |def_map, local_id| {
281 def_map[local_id].scope.names_of(item, |name, _, declared| {
282 (declared || !ignore_local_imports).then(|| name.clone())
283 })
284 })
285}
286
287fn find_in_prelude(
290 db: &dyn SourceDatabase,
291 local_def_map: &DefMap,
292 item: ItemInNs,
293 from: ModuleIdLt<'_>,
294) -> Option<Choice> {
295 let (prelude_module, _) = local_def_map.prelude()?;
296 let prelude_def_map = prelude_module.def_map(db);
297 let prelude_scope = &prelude_def_map[prelude_module].scope;
298 let (name, vis, _declared) = prelude_scope.name_of(item)?;
299 if !vis.is_visible_from(db, from) {
300 return None;
301 }
302
303 let found_and_same_def =
305 local_def_map.with_ancestor_maps(db, from, &mut |def_map, local_id| {
306 let per_ns = def_map[local_id].scope.get(name);
307 let same_def = match item {
308 ItemInNs::Types(it) => per_ns.take_types()? == it,
309 ItemInNs::Values(it) => per_ns.take_values()? == it,
310 ItemInNs::Macros(it) => per_ns.take_macros()? == it,
311 };
312 Some(same_def)
313 });
314
315 if found_and_same_def.unwrap_or(true) {
316 Some(Choice::new(PathKind::Plain, name.clone(), Stable))
317 } else {
318 None
319 }
320}
321
322fn is_kw_kind_relative_to_from(
323 db: &dyn SourceDatabase,
324 def_map: &DefMap,
325 item: ModuleIdLt<'_>,
326 from: ModuleIdLt<'_>,
327) -> Option<PathKind> {
328 if item.krate(db) != from.krate(db) || item.block(db).is_some() || from.block(db).is_some() {
329 return None;
330 }
331 if item == from {
332 Some(PathKind::SELF)
334 } else if let Some(parent_id) = def_map[from].parent {
335 if item == parent_id {
336 Some(if parent_id == def_map.root { PathKind::Crate } else { PathKind::Super(1) })
338 } else {
339 None
340 }
341 } else {
342 None
343 }
344}
345
346#[tracing::instrument(skip_all)]
347fn calculate_best_path<'db>(
348 ctx: &'db FindPathCtx<'db>,
349 visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
350 item: ItemInNs,
351 max_len: usize,
352 best_choice: &mut Option<Choice>,
353) {
354 let fuel = ctx.fuel.get();
355 if fuel == 0 {
356 tracing::warn!(
358 "ran out of fuel while searching for a path for item {item:?} of krate {:?} from krate {:?}",
359 item.krate(ctx.db),
360 ctx.from_crate
361 );
362 return;
363 }
364 ctx.fuel.set(fuel - 1);
365
366 if item.krate(ctx.db) == Some(ctx.from_crate) {
367 calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice)
370 } else if ctx.is_std_item {
371 find_in_sysroot(ctx, visited_modules, item, max_len, best_choice)
376 } else {
377 ctx.from_crate.data(ctx.db).dependencies.iter().for_each(|dep| {
382 find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id)
383 });
384 }
385}
386
387fn find_in_sysroot<'db>(
388 ctx: &'db FindPathCtx<'db>,
389 visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
390 item: ItemInNs,
391 max_len: usize,
392 best_choice: &mut Option<Choice>,
393) {
394 let dependencies = &ctx.from_crate.data(ctx.db).dependencies;
395 let mut search = |lang, best_choice: &mut _| {
396 if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| {
397 match dep.crate_id.data(ctx.db).origin {
398 CrateOrigin::Lang(l) => l == lang,
399 _ => false,
400 }
401 }) {
402 find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id);
403 }
404 };
405 if ctx.cfg.prefer_no_std {
406 search(LangCrateOrigin::Core, best_choice);
407 if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
408 return;
409 }
410 search(LangCrateOrigin::Alloc, best_choice);
411 if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
412 return;
413 }
414 search(LangCrateOrigin::Std, best_choice);
415 if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
416 return;
417 }
418 } else {
419 search(LangCrateOrigin::Std, best_choice);
420 if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
421 return;
422 }
423 search(LangCrateOrigin::Core, best_choice);
424 if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
425 return;
426 }
427 search(LangCrateOrigin::Alloc, best_choice);
428 if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
429 return;
430 }
431 }
432 dependencies
433 .iter()
434 .filter(|it| it.is_sysroot())
435 .chain(dependencies.iter().filter(|it| !it.is_sysroot()))
436 .for_each(|dep| {
437 find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id);
438 });
439}
440
441fn find_in_dep<'db>(
442 ctx: &'db FindPathCtx<'db>,
443 visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
444 item: ItemInNs,
445 max_len: usize,
446 best_choice: &mut Option<Choice>,
447 dep: Crate,
448) {
449 let import_map = ImportMap::of(ctx.db, dep);
450 let Some(import_info_for) = import_map.import_info_for(item) else {
451 return;
452 };
453 for info in import_info_for {
454 if info.is_doc_hidden {
455 continue;
457 }
458
459 let choice = find_path_for_module(ctx, visited_modules, info.container, true, max_len - 1);
462 let Some(mut choice) = choice else {
463 continue;
464 };
465 cov_mark::hit!(partially_imported);
466 if info.is_unstable {
467 if !ctx.cfg.allow_unstable {
468 continue;
470 }
471 choice.stability = Unstable;
472 }
473
474 Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, info.name.clone());
475 }
476}
477
478fn calculate_best_path_local<'db>(
479 ctx: &'db FindPathCtx<'db>,
480 visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
481 item: ItemInNs,
482 max_len: usize,
483 best_choice: &mut Option<Choice>,
484) {
485 find_local_import_locations(ctx, item, visited_modules, |visited_modules, name, module_id| {
487 if let Some(choice) =
490 find_path_for_module(ctx, visited_modules, module_id, false, max_len - 1)
491 {
492 Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, name.clone());
493 }
494 });
495}
496
497#[derive(Debug)]
498struct Choice {
499 path: ModPath,
500 path_text_len: usize,
502 stability: Stability,
504 has_prelude_segment: bool,
506}
507
508impl Choice {
509 fn new(kind: PathKind, name: Name, stability: Stability) -> Self {
510 Self {
511 path_text_len: path_kind_len(kind) + name.as_str().len(),
512 stability,
513 has_prelude_segment: name == sym::prelude,
514 path: ModPath::from_segments(kind, iter::once(name)),
515 }
516 }
517
518 fn push(mut self, name: Name) -> Self {
519 self.path_text_len += name.as_str().len();
520 self.has_prelude_segment |= name == sym::prelude;
521 self.path.push_segment(name);
522 self
523 }
524
525 fn try_select(
526 current: &mut Option<Choice>,
527 mut other: Choice,
528 prefer_prelude: bool,
529 name: Name,
530 ) {
531 let Some(current) = current else {
532 *current = Some(other.push(name));
533 return;
534 };
535 match other
536 .stability
537 .cmp(¤t.stability)
538 .then_with(|| {
539 if prefer_prelude {
540 other.has_prelude_segment.cmp(¤t.has_prelude_segment)
541 } else {
542 current.has_prelude_segment.cmp(&other.has_prelude_segment)
543 }
544 })
545 .then_with(|| (current.path.len()).cmp(&(other.path.len() + 1)))
546 {
547 Ordering::Less => return,
548 Ordering::Equal => {
549 other.path_text_len += name.as_str().len();
550 if let Ordering::Less | Ordering::Equal =
551 current.path_text_len.cmp(&other.path_text_len)
552 {
553 return;
554 }
555 }
556 Ordering::Greater => {
557 other.path_text_len += name.as_str().len();
558 }
559 }
560 other.path.push_segment(name);
561 *current = other;
562 }
563}
564
565fn path_kind_len(kind: PathKind) -> usize {
566 match kind {
567 PathKind::Plain => 0,
568 PathKind::Super(0) => 4,
569 PathKind::Super(s) => s as usize * 5,
570 PathKind::Crate => 5,
571 PathKind::Abs => 2,
572 PathKind::DollarCrate(_) => 0,
573 }
574}
575
576fn find_local_import_locations<'db>(
578 ctx: &'db FindPathCtx<'db>,
579 item: ItemInNs,
580 visited_modules: &mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>,
581 mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleIdLt<'db>)>, &Name, ModuleIdLt<'db>),
582) {
583 let _p = tracing::info_span!("find_local_import_locations").entered();
584 let db = ctx.db;
585
586 let mut worklist = ctx.from_def_map[ctx.from]
593 .children
594 .values()
595 .copied()
596 .chain(iter::successors(ctx.from.containing_module(db), |m| m.containing_module(db)))
597 .zip(iter::repeat(false))
598 .collect::<Vec<_>>();
599
600 let def_map =
601 if ctx.crate_root == ctx.from { ctx.from_def_map } else { ctx.crate_root.def_map(db) };
602 let mut block_def_map;
603 let mut cursor = 0;
604
605 while let Some(&mut (module, ref mut processed)) = worklist.get_mut(cursor) {
606 cursor += 1;
607 if !visited_modules.insert((item, module)) {
608 continue;
610 }
611 *processed = true;
612 let data = if module.block(db).is_some() {
613 block_def_map = module.def_map(db);
615 &block_def_map[module]
616 } else {
617 &def_map[module]
619 };
620
621 if let Some((name, vis, declared)) = data.scope.name_of(item)
622 && vis.is_visible_from(db, ctx.from)
623 {
624 let is_pub_or_explicit = match vis {
625 Visibility::Module(_, VisibilityExplicitness::Explicit) => {
626 cov_mark::hit!(explicit_private_imports);
627 true
628 }
629 Visibility::Module(_, VisibilityExplicitness::Implicit) => {
630 cov_mark::hit!(discount_private_imports);
631 false
632 }
633 Visibility::PubCrate(_) => true,
634 Visibility::Public => true,
635 };
636
637 if declared || is_pub_or_explicit {
643 cb(visited_modules, name, module);
644 }
645 }
646
647 for (module, vis) in data.scope.modules_in_scope() {
649 if module.krate(db) != ctx.from.krate(db) {
650 continue;
653 }
654 if visited_modules.contains(&(item, module)) {
655 continue;
656 }
657
658 if vis.is_visible_from(db, ctx.from) {
659 worklist.push((module, false));
660 }
661 }
662 }
663 worklist.into_iter().filter(|&(_, processed)| processed).for_each(|(module, _)| {
664 visited_modules.remove(&(item, module));
665 });
666}
667
668#[cfg(test)]
669mod tests {
670 use std::cell::LazyCell;
671
672 use expect_test::{Expect, expect};
673 use itertools::Itertools;
674 use span::Edition;
675 use stdx::format_to;
676 use syntax::ast::AstNode;
677 use test_fixture::WithFixture;
678
679 use crate::test_db::TestDB;
680
681 use super::*;
682
683 #[track_caller]
687 fn check_found_path_(
688 #[rust_analyzer::rust_fixture] ra_fixture: &str,
689 path: &str,
690 prefer_prelude: bool,
691 prefer_absolute: bool,
692 prefer_no_std: bool,
693 allow_unstable: bool,
694 expect: Expect,
695 ) {
696 let (db, pos) = TestDB::with_position(ra_fixture);
697 let module = db.module_at_position(pos);
698 let parsed_path_file =
699 syntax::SourceFile::parse(&format!("use {path};"), span::Edition::CURRENT);
700 let ast_path =
701 parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap();
702 let span_map = LazyCell::new(|| hir_expand::HirFileId::from(pos.file_id).span_map(&db));
703 let mod_path =
704 ModPath::from_src(&db, ast_path, &mut |range| span_map.span_for_range(range).ctx)
705 .unwrap();
706
707 let (def_map, local_def_map) = module.local_def_map(&db);
708 let resolved = def_map
709 .resolve_path(
710 local_def_map,
711 &db,
712 module,
713 &mod_path,
714 crate::item_scope::BuiltinShadowMode::Module,
715 None,
716 )
717 .0;
718 let resolved = resolved
719 .take_types()
720 .map(ItemInNs::Types)
721 .or_else(|| resolved.take_values().map(ItemInNs::Values))
722 .expect("path does not resolve to a type or value");
723
724 let mut res = String::new();
725 for (prefix, ignore_local_imports) in
726 [PrefixKind::Plain, PrefixKind::ByCrate, PrefixKind::BySelf]
727 .into_iter()
728 .cartesian_product([false, true])
729 {
730 let found_path = find_path(
731 &db,
732 resolved,
733 module,
734 prefix,
735 ignore_local_imports,
736 FindPathConfig { prefer_no_std, prefer_prelude, prefer_absolute, allow_unstable },
737 );
738 format_to!(
739 res,
740 "{:7}(imports {}): {}\n",
741 format!("{:?}", prefix),
742 if ignore_local_imports { '✖' } else { '✔' },
743 found_path.map_or_else(
744 || "<unresolvable>".to_owned(),
745 |it| it.display(&db, Edition::CURRENT).to_string()
746 ),
747 );
748 }
749 expect.assert_eq(&res);
750 }
751
752 fn check_found_path(
753 #[rust_analyzer::rust_fixture] ra_fixture: &str,
754 path: &str,
755 expect: Expect,
756 ) {
757 check_found_path_(ra_fixture, path, false, false, false, false, expect);
758 }
759
760 fn check_found_path_prelude(
761 #[rust_analyzer::rust_fixture] ra_fixture: &str,
762 path: &str,
763 expect: Expect,
764 ) {
765 check_found_path_(ra_fixture, path, true, false, false, false, expect);
766 }
767
768 fn check_found_path_absolute(
769 #[rust_analyzer::rust_fixture] ra_fixture: &str,
770 path: &str,
771 expect: Expect,
772 ) {
773 check_found_path_(ra_fixture, path, false, true, false, false, expect);
774 }
775
776 fn check_found_path_prefer_no_std(
777 #[rust_analyzer::rust_fixture] ra_fixture: &str,
778 path: &str,
779 expect: Expect,
780 ) {
781 check_found_path_(ra_fixture, path, false, false, true, false, expect);
782 }
783
784 fn check_found_path_prefer_no_std_allow_unstable(
785 #[rust_analyzer::rust_fixture] ra_fixture: &str,
786 path: &str,
787 expect: Expect,
788 ) {
789 check_found_path_(ra_fixture, path, false, false, true, true, expect);
790 }
791
792 #[test]
793 fn same_module() {
794 check_found_path(
795 r#"
796struct S;
797$0
798 "#,
799 "S",
800 expect![[r#"
801 Plain (imports ✔): S
802 Plain (imports ✖): S
803 ByCrate(imports ✔): crate::S
804 ByCrate(imports ✖): crate::S
805 BySelf (imports ✔): self::S
806 BySelf (imports ✖): self::S
807 "#]],
808 );
809 }
810
811 #[test]
812 fn enum_variant() {
813 check_found_path(
814 r#"
815enum E { A }
816$0
817 "#,
818 "E::A",
819 expect![[r#"
820 Plain (imports ✔): E::A
821 Plain (imports ✖): E::A
822 ByCrate(imports ✔): crate::E::A
823 ByCrate(imports ✖): crate::E::A
824 BySelf (imports ✔): self::E::A
825 BySelf (imports ✖): self::E::A
826 "#]],
827 );
828 }
829
830 #[test]
831 fn sub_module() {
832 check_found_path(
833 r#"
834mod foo {
835 pub struct S;
836}
837$0
838 "#,
839 "foo::S",
840 expect![[r#"
841 Plain (imports ✔): foo::S
842 Plain (imports ✖): foo::S
843 ByCrate(imports ✔): crate::foo::S
844 ByCrate(imports ✖): crate::foo::S
845 BySelf (imports ✔): self::foo::S
846 BySelf (imports ✖): self::foo::S
847 "#]],
848 );
849 }
850
851 #[test]
852 fn super_module() {
853 check_found_path(
854 r#"
855//- /main.rs
856mod foo;
857//- /foo.rs
858mod bar;
859struct S;
860//- /foo/bar.rs
861$0
862 "#,
863 "super::S",
864 expect![[r#"
865 Plain (imports ✔): super::S
866 Plain (imports ✖): super::S
867 ByCrate(imports ✔): crate::foo::S
868 ByCrate(imports ✖): crate::foo::S
869 BySelf (imports ✔): super::S
870 BySelf (imports ✖): super::S
871 "#]],
872 );
873 }
874
875 #[test]
876 fn self_module() {
877 check_found_path(
878 r#"
879//- /main.rs
880mod foo;
881//- /foo.rs
882$0
883 "#,
884 "self",
885 expect![[r#"
886 Plain (imports ✔): self
887 Plain (imports ✖): self
888 ByCrate(imports ✔): crate::foo
889 ByCrate(imports ✖): crate::foo
890 BySelf (imports ✔): self
891 BySelf (imports ✖): self
892 "#]],
893 );
894 }
895
896 #[test]
897 fn crate_root() {
898 check_found_path(
899 r#"
900//- /main.rs
901mod foo;
902//- /foo.rs
903$0
904 "#,
905 "crate",
906 expect![[r#"
907 Plain (imports ✔): crate
908 Plain (imports ✖): crate
909 ByCrate(imports ✔): crate
910 ByCrate(imports ✖): crate
911 BySelf (imports ✔): crate
912 BySelf (imports ✖): crate
913 "#]],
914 );
915 }
916
917 #[test]
918 fn same_crate() {
919 check_found_path(
920 r#"
921//- /main.rs
922mod foo;
923struct S;
924//- /foo.rs
925$0
926 "#,
927 "crate::S",
928 expect![[r#"
929 Plain (imports ✔): crate::S
930 Plain (imports ✖): crate::S
931 ByCrate(imports ✔): crate::S
932 ByCrate(imports ✖): crate::S
933 BySelf (imports ✔): crate::S
934 BySelf (imports ✖): crate::S
935 "#]],
936 );
937 }
938
939 #[test]
940 fn different_crate() {
941 check_found_path(
942 r#"
943//- /main.rs crate:main deps:std
944$0
945//- /std.rs crate:std
946pub struct S;
947 "#,
948 "std::S",
949 expect![[r#"
950 Plain (imports ✔): std::S
951 Plain (imports ✖): std::S
952 ByCrate(imports ✔): std::S
953 ByCrate(imports ✖): std::S
954 BySelf (imports ✔): std::S
955 BySelf (imports ✖): std::S
956 "#]],
957 );
958 }
959
960 #[test]
961 fn different_crate_renamed() {
962 check_found_path(
963 r#"
964//- /main.rs crate:main deps:std
965extern crate std as std_renamed;
966$0
967//- /std.rs crate:std
968pub struct S;
969 "#,
970 "std_renamed::S",
971 expect![[r#"
972 Plain (imports ✔): std_renamed::S
973 Plain (imports ✖): std_renamed::S
974 ByCrate(imports ✔): std_renamed::S
975 ByCrate(imports ✖): std_renamed::S
976 BySelf (imports ✔): std_renamed::S
977 BySelf (imports ✖): std_renamed::S
978 "#]],
979 );
980 }
981
982 #[test]
983 fn partially_imported() {
984 cov_mark::check!(partially_imported);
985 check_found_path(
988 r#"
989//- /main.rs crate:main deps:syntax
990
991use syntax::ast;
992$0
993
994//- /lib.rs crate:syntax
995pub mod ast {
996 pub enum ModuleItem {
997 A, B, C,
998 }
999}
1000 "#,
1001 "syntax::ast::ModuleItem",
1002 expect![[r#"
1003 Plain (imports ✔): ast::ModuleItem
1004 Plain (imports ✖): syntax::ast::ModuleItem
1005 ByCrate(imports ✔): crate::ast::ModuleItem
1006 ByCrate(imports ✖): syntax::ast::ModuleItem
1007 BySelf (imports ✔): self::ast::ModuleItem
1008 BySelf (imports ✖): syntax::ast::ModuleItem
1009 "#]],
1010 );
1011
1012 check_found_path(
1013 r#"
1014//- /main.rs crate:main deps:syntax
1015$0
1016
1017//- /lib.rs crate:syntax
1018pub mod ast {
1019 pub enum ModuleItem {
1020 A, B, C,
1021 }
1022}
1023 "#,
1024 "syntax::ast::ModuleItem",
1025 expect![[r#"
1026 Plain (imports ✔): syntax::ast::ModuleItem
1027 Plain (imports ✖): syntax::ast::ModuleItem
1028 ByCrate(imports ✔): syntax::ast::ModuleItem
1029 ByCrate(imports ✖): syntax::ast::ModuleItem
1030 BySelf (imports ✔): syntax::ast::ModuleItem
1031 BySelf (imports ✖): syntax::ast::ModuleItem
1032 "#]],
1033 );
1034 }
1035
1036 #[test]
1037 fn partially_imported_with_prefer_absolute() {
1038 cov_mark::check!(partially_imported);
1039 check_found_path_absolute(
1044 r#"
1045//- /main.rs crate:main deps:syntax
1046
1047use syntax::ast;
1048$0
1049
1050//- /lib.rs crate:syntax
1051pub mod ast {
1052 pub enum ModuleItem {
1053 A, B, C,
1054 }
1055}
1056 "#,
1057 "syntax::ast::ModuleItem",
1058 expect![[r#"
1059 Plain (imports ✔): ast::ModuleItem
1060 Plain (imports ✖): ::syntax::ast::ModuleItem
1061 ByCrate(imports ✔): crate::ast::ModuleItem
1062 ByCrate(imports ✖): ::syntax::ast::ModuleItem
1063 BySelf (imports ✔): self::ast::ModuleItem
1064 BySelf (imports ✖): ::syntax::ast::ModuleItem
1065 "#]],
1066 );
1067 }
1068
1069 #[test]
1070 fn same_crate_reexport() {
1071 check_found_path(
1072 r#"
1073mod bar {
1074 mod foo { pub(crate) struct S; }
1075 pub(crate) use foo::*;
1076}
1077$0
1078 "#,
1079 "bar::S",
1080 expect![[r#"
1081 Plain (imports ✔): bar::S
1082 Plain (imports ✖): bar::S
1083 ByCrate(imports ✔): crate::bar::S
1084 ByCrate(imports ✖): crate::bar::S
1085 BySelf (imports ✔): self::bar::S
1086 BySelf (imports ✖): self::bar::S
1087 "#]],
1088 );
1089 }
1090
1091 #[test]
1092 fn same_crate_reexport_rename() {
1093 check_found_path(
1094 r#"
1095mod bar {
1096 mod foo { pub(crate) struct S; }
1097 pub(crate) use foo::S as U;
1098}
1099$0
1100 "#,
1101 "bar::U",
1102 expect![[r#"
1103 Plain (imports ✔): bar::U
1104 Plain (imports ✖): bar::U
1105 ByCrate(imports ✔): crate::bar::U
1106 ByCrate(imports ✖): crate::bar::U
1107 BySelf (imports ✔): self::bar::U
1108 BySelf (imports ✖): self::bar::U
1109 "#]],
1110 );
1111 }
1112
1113 #[test]
1114 fn different_crate_reexport() {
1115 check_found_path(
1116 r#"
1117//- /main.rs crate:main deps:std
1118$0
1119//- /std.rs crate:std deps:core
1120pub use core::S;
1121//- /core.rs crate:core
1122pub struct S;
1123 "#,
1124 "std::S",
1125 expect![[r#"
1126 Plain (imports ✔): std::S
1127 Plain (imports ✖): std::S
1128 ByCrate(imports ✔): std::S
1129 ByCrate(imports ✖): std::S
1130 BySelf (imports ✔): std::S
1131 BySelf (imports ✖): std::S
1132 "#]],
1133 );
1134 }
1135
1136 #[test]
1137 fn prelude() {
1138 check_found_path(
1139 r#"
1140//- /main.rs edition:2018 crate:main deps:std
1141$0
1142//- /std.rs crate:std
1143pub mod prelude {
1144 pub mod rust_2018 {
1145 pub struct S;
1146 }
1147}
1148 "#,
1149 "S",
1150 expect![[r#"
1151 Plain (imports ✔): S
1152 Plain (imports ✖): S
1153 ByCrate(imports ✔): S
1154 ByCrate(imports ✖): S
1155 BySelf (imports ✔): S
1156 BySelf (imports ✖): S
1157 "#]],
1158 );
1159 }
1160
1161 #[test]
1162 fn shadowed_prelude() {
1163 check_found_path(
1164 r#"
1165//- /main.rs crate:main deps:std
1166struct S;
1167$0
1168//- /std.rs crate:std
1169pub mod prelude {
1170 pub mod rust_2018 {
1171 pub struct S;
1172 }
1173}
1174"#,
1175 "std::prelude::rust_2018::S",
1176 expect![[r#"
1177 Plain (imports ✔): std::prelude::rust_2018::S
1178 Plain (imports ✖): std::prelude::rust_2018::S
1179 ByCrate(imports ✔): std::prelude::rust_2018::S
1180 ByCrate(imports ✖): std::prelude::rust_2018::S
1181 BySelf (imports ✔): std::prelude::rust_2018::S
1182 BySelf (imports ✖): std::prelude::rust_2018::S
1183 "#]],
1184 );
1185 }
1186
1187 #[test]
1188 fn imported_prelude() {
1189 check_found_path(
1190 r#"
1191//- /main.rs edition:2018 crate:main deps:std
1192use S;
1193$0
1194//- /std.rs crate:std
1195pub mod prelude {
1196 pub mod rust_2018 {
1197 pub struct S;
1198 }
1199}
1200"#,
1201 "S",
1202 expect![[r#"
1203 Plain (imports ✔): S
1204 Plain (imports ✖): S
1205 ByCrate(imports ✔): crate::S
1206 ByCrate(imports ✖): S
1207 BySelf (imports ✔): self::S
1208 BySelf (imports ✖): S
1209 "#]],
1210 );
1211 }
1212
1213 #[test]
1214 fn enum_variant_from_prelude() {
1215 let code = r#"
1216//- /main.rs edition:2018 crate:main deps:std
1217$0
1218//- /std.rs crate:std
1219pub mod prelude {
1220 pub mod rust_2018 {
1221 pub enum Option<T> { Some(T), None }
1222 pub use Option::*;
1223 }
1224}
1225 "#;
1226 check_found_path(
1227 code,
1228 "None",
1229 expect![[r#"
1230 Plain (imports ✔): None
1231 Plain (imports ✖): None
1232 ByCrate(imports ✔): None
1233 ByCrate(imports ✖): None
1234 BySelf (imports ✔): None
1235 BySelf (imports ✖): None
1236 "#]],
1237 );
1238 check_found_path(
1239 code,
1240 "Some",
1241 expect![[r#"
1242 Plain (imports ✔): Some
1243 Plain (imports ✖): Some
1244 ByCrate(imports ✔): Some
1245 ByCrate(imports ✖): Some
1246 BySelf (imports ✔): Some
1247 BySelf (imports ✖): Some
1248 "#]],
1249 );
1250 }
1251
1252 #[test]
1253 fn shortest_path() {
1254 check_found_path(
1255 r#"
1256//- /main.rs
1257pub mod foo;
1258pub mod baz;
1259struct S;
1260$0
1261//- /foo.rs
1262pub mod bar { pub struct S; }
1263//- /baz.rs
1264pub use crate::foo::bar::S;
1265 "#,
1266 "baz::S",
1267 expect![[r#"
1268 Plain (imports ✔): baz::S
1269 Plain (imports ✖): baz::S
1270 ByCrate(imports ✔): crate::baz::S
1271 ByCrate(imports ✖): crate::baz::S
1272 BySelf (imports ✔): self::baz::S
1273 BySelf (imports ✖): self::baz::S
1274 "#]],
1275 );
1276 }
1277
1278 #[test]
1279 fn discount_private_imports() {
1280 cov_mark::check!(discount_private_imports);
1281 check_found_path(
1282 r#"
1283//- /main.rs
1284mod foo;
1285pub mod bar { pub struct S; }
1286use bar::S;
1287//- /foo.rs
1288$0
1289 "#,
1290 "crate::bar::S",
1292 expect![[r#"
1293 Plain (imports ✔): crate::bar::S
1294 Plain (imports ✖): crate::bar::S
1295 ByCrate(imports ✔): crate::bar::S
1296 ByCrate(imports ✖): crate::bar::S
1297 BySelf (imports ✔): crate::bar::S
1298 BySelf (imports ✖): crate::bar::S
1299 "#]],
1300 );
1301 }
1302
1303 #[test]
1304 fn explicit_private_imports_crate() {
1305 check_found_path(
1306 r#"
1307//- /main.rs
1308mod foo;
1309pub mod bar { pub struct S; }
1310pub(crate) use bar::S;
1311//- /foo.rs
1312$0
1313 "#,
1314 "crate::S",
1315 expect![[r#"
1316 Plain (imports ✔): crate::S
1317 Plain (imports ✖): crate::S
1318 ByCrate(imports ✔): crate::S
1319 ByCrate(imports ✖): crate::S
1320 BySelf (imports ✔): crate::S
1321 BySelf (imports ✖): crate::S
1322 "#]],
1323 );
1324 }
1325
1326 #[test]
1327 fn explicit_private_imports() {
1328 cov_mark::check!(explicit_private_imports);
1329 check_found_path(
1330 r#"
1331//- /main.rs
1332pub mod bar {
1333 mod foo;
1334 pub mod baz { pub struct S; }
1335 pub(self) use baz::S;
1336}
1337
1338//- /bar/foo.rs
1339$0
1340 "#,
1341 "super::S",
1342 expect![[r#"
1343 Plain (imports ✔): super::S
1344 Plain (imports ✖): super::S
1345 ByCrate(imports ✔): crate::bar::S
1346 ByCrate(imports ✖): crate::bar::S
1347 BySelf (imports ✔): super::S
1348 BySelf (imports ✖): super::S
1349 "#]],
1350 );
1351 }
1352
1353 #[test]
1354 fn import_cycle() {
1355 check_found_path(
1356 r#"
1357//- /main.rs
1358pub mod foo;
1359pub mod bar;
1360pub mod baz;
1361//- /bar.rs
1362$0
1363//- /foo.rs
1364pub use super::baz;
1365pub struct S;
1366//- /baz.rs
1367pub use super::foo;
1368 "#,
1369 "crate::foo::S",
1370 expect![[r#"
1371 Plain (imports ✔): crate::foo::S
1372 Plain (imports ✖): crate::foo::S
1373 ByCrate(imports ✔): crate::foo::S
1374 ByCrate(imports ✖): crate::foo::S
1375 BySelf (imports ✔): crate::foo::S
1376 BySelf (imports ✖): crate::foo::S
1377 "#]],
1378 );
1379 }
1380
1381 #[test]
1382 fn prefer_std_paths_over_alloc() {
1383 check_found_path(
1384 r#"
1385//- /main.rs crate:main deps:alloc,std
1386$0
1387
1388//- /std.rs crate:std deps:alloc
1389pub mod sync {
1390 pub use alloc::sync::Arc;
1391}
1392
1393//- /zzz.rs crate:alloc
1394pub mod sync {
1395 pub struct Arc;
1396}
1397 "#,
1398 "std::sync::Arc",
1399 expect![[r#"
1400 Plain (imports ✔): std::sync::Arc
1401 Plain (imports ✖): std::sync::Arc
1402 ByCrate(imports ✔): std::sync::Arc
1403 ByCrate(imports ✖): std::sync::Arc
1404 BySelf (imports ✔): std::sync::Arc
1405 BySelf (imports ✖): std::sync::Arc
1406 "#]],
1407 );
1408 }
1409 #[test]
1410 fn prefer_core_paths_over_std_for_mod_reexport() {
1411 check_found_path_prefer_no_std(
1412 r#"
1413//- /main.rs crate:main deps:core,std
1414
1415$0
1416
1417//- /stdlib.rs crate:std deps:core
1418
1419pub use core::pin;
1420
1421//- /corelib.rs crate:core
1422
1423pub mod pin {
1424 pub struct Pin;
1425}
1426 "#,
1427 "std::pin::Pin",
1428 expect![[r#"
1429 Plain (imports ✔): core::pin::Pin
1430 Plain (imports ✖): core::pin::Pin
1431 ByCrate(imports ✔): core::pin::Pin
1432 ByCrate(imports ✖): core::pin::Pin
1433 BySelf (imports ✔): core::pin::Pin
1434 BySelf (imports ✖): core::pin::Pin
1435 "#]],
1436 );
1437 }
1438
1439 #[test]
1440 fn prefer_core_paths_over_std() {
1441 check_found_path_prefer_no_std(
1442 r#"
1443//- /main.rs crate:main deps:core,std
1444
1445$0
1446
1447//- /std.rs crate:std deps:core
1448
1449pub mod fmt {
1450 pub use core::fmt::Error;
1451}
1452
1453//- /zzz.rs crate:core
1454
1455pub mod fmt {
1456 pub struct Error;
1457}
1458 "#,
1459 "core::fmt::Error",
1460 expect![[r#"
1461 Plain (imports ✔): core::fmt::Error
1462 Plain (imports ✖): core::fmt::Error
1463 ByCrate(imports ✔): core::fmt::Error
1464 ByCrate(imports ✖): core::fmt::Error
1465 BySelf (imports ✔): core::fmt::Error
1466 BySelf (imports ✖): core::fmt::Error
1467 "#]],
1468 );
1469 check_found_path(
1470 r#"
1471//- /main.rs crate:main deps:core,std
1472#![no_std]
1473
1474$0
1475
1476//- /std.rs crate:std deps:core
1477
1478pub mod fmt {
1479 pub use core::fmt::Error;
1480}
1481
1482//- /zzz.rs crate:core
1483
1484pub mod fmt {
1485 pub struct Error;
1486}
1487 "#,
1488 "core::fmt::Error",
1489 expect![[r#"
1490 Plain (imports ✔): core::fmt::Error
1491 Plain (imports ✖): core::fmt::Error
1492 ByCrate(imports ✔): core::fmt::Error
1493 ByCrate(imports ✖): core::fmt::Error
1494 BySelf (imports ✔): core::fmt::Error
1495 BySelf (imports ✖): core::fmt::Error
1496 "#]],
1497 );
1498
1499 check_found_path(
1501 r#"
1502//- /main.rs crate:main deps:core,std
1503#![cfg_attr(not(test), no_std)]
1504
1505$0
1506
1507//- /std.rs crate:std deps:core
1508
1509pub mod fmt {
1510 pub use core::fmt::Error;
1511}
1512
1513//- /zzz.rs crate:core
1514
1515pub mod fmt {
1516 pub struct Error;
1517}
1518 "#,
1519 "core::fmt::Error",
1520 expect![[r#"
1521 Plain (imports ✔): core::fmt::Error
1522 Plain (imports ✖): core::fmt::Error
1523 ByCrate(imports ✔): core::fmt::Error
1524 ByCrate(imports ✖): core::fmt::Error
1525 BySelf (imports ✔): core::fmt::Error
1526 BySelf (imports ✖): core::fmt::Error
1527 "#]],
1528 );
1529
1530 check_found_path(
1532 r#"
1533//- /main.rs crate:main deps:core,std cfg:test
1534#![cfg_attr(not(test), no_std)]
1535
1536$0
1537
1538//- /std.rs crate:std deps:core
1539
1540pub mod fmt {
1541 pub use core::fmt::Error;
1542}
1543
1544//- /zzz.rs crate:core
1545
1546pub mod fmt {
1547 pub struct Error;
1548}
1549 "#,
1550 "core::fmt::Error",
1551 expect![[r#"
1552 Plain (imports ✔): core::fmt::Error
1553 Plain (imports ✖): core::fmt::Error
1554 ByCrate(imports ✔): core::fmt::Error
1555 ByCrate(imports ✖): core::fmt::Error
1556 BySelf (imports ✔): core::fmt::Error
1557 BySelf (imports ✖): core::fmt::Error
1558 "#]],
1559 );
1560 }
1561
1562 #[test]
1563 fn prefer_alloc_paths_over_std() {
1564 check_found_path(
1565 r#"
1566//- /main.rs crate:main deps:alloc,std
1567#![no_std]
1568
1569extern crate alloc;
1570
1571$0
1572
1573//- /std.rs crate:std deps:alloc
1574
1575pub mod sync {
1576 pub use alloc::sync::Arc;
1577}
1578
1579//- /zzz.rs crate:alloc
1580
1581pub mod sync {
1582 pub struct Arc;
1583}
1584 "#,
1585 "alloc::sync::Arc",
1586 expect![[r#"
1587 Plain (imports ✔): alloc::sync::Arc
1588 Plain (imports ✖): alloc::sync::Arc
1589 ByCrate(imports ✔): alloc::sync::Arc
1590 ByCrate(imports ✖): alloc::sync::Arc
1591 BySelf (imports ✔): alloc::sync::Arc
1592 BySelf (imports ✖): alloc::sync::Arc
1593 "#]],
1594 );
1595 }
1596
1597 #[test]
1598 fn prefer_alloc_paths_over_std_with_extern_crate_std() {
1599 check_found_path(
1600 r#"
1601//- /main.rs crate:main deps:alloc,std
1602#![no_std]
1603
1604extern crate alloc;
1605
1606extern crate std;
1607
1608$0
1609
1610//- /std.rs crate:std deps:alloc
1611
1612pub mod sync {
1613 pub use alloc::sync::Arc;
1614}
1615
1616//- /zzz.rs crate:alloc
1617
1618pub mod sync {
1619 pub struct Arc;
1620}
1621 "#,
1622 "alloc::sync::Arc",
1623 expect![[r#"
1624 Plain (imports ✔): alloc::sync::Arc
1625 Plain (imports ✖): alloc::sync::Arc
1626 ByCrate(imports ✔): alloc::sync::Arc
1627 ByCrate(imports ✖): alloc::sync::Arc
1628 BySelf (imports ✔): alloc::sync::Arc
1629 BySelf (imports ✖): alloc::sync::Arc
1630 "#]],
1631 );
1632 }
1633
1634 #[test]
1635 fn prefer_shorter_paths_if_not_alloc() {
1636 check_found_path(
1637 r#"
1638//- /main.rs crate:main deps:megaalloc,std
1639$0
1640
1641//- /std.rs crate:std deps:megaalloc
1642pub mod sync {
1643 pub use megaalloc::sync::Arc;
1644}
1645
1646//- /zzz.rs crate:megaalloc
1647pub struct Arc;
1648 "#,
1649 "megaalloc::Arc",
1650 expect![[r#"
1651 Plain (imports ✔): megaalloc::Arc
1652 Plain (imports ✖): megaalloc::Arc
1653 ByCrate(imports ✔): megaalloc::Arc
1654 ByCrate(imports ✖): megaalloc::Arc
1655 BySelf (imports ✔): megaalloc::Arc
1656 BySelf (imports ✖): megaalloc::Arc
1657 "#]],
1658 );
1659 }
1660
1661 #[test]
1662 fn builtins_are_in_scope() {
1663 let code = r#"
1664$0
1665
1666pub mod primitive {
1667 pub use u8;
1668}
1669 "#;
1670 check_found_path(
1671 code,
1672 "u8",
1673 expect![[r#"
1674 Plain (imports ✔): u8
1675 Plain (imports ✖): u8
1676 ByCrate(imports ✔): u8
1677 ByCrate(imports ✖): u8
1678 BySelf (imports ✔): u8
1679 BySelf (imports ✖): u8
1680 "#]],
1681 );
1682 check_found_path(
1683 code,
1684 "u16",
1685 expect![[r#"
1686 Plain (imports ✔): u16
1687 Plain (imports ✖): u16
1688 ByCrate(imports ✔): u16
1689 ByCrate(imports ✖): u16
1690 BySelf (imports ✔): u16
1691 BySelf (imports ✖): u16
1692 "#]],
1693 );
1694 }
1695
1696 #[test]
1697 fn inner_items() {
1698 check_found_path(
1699 r#"
1700fn main() {
1701 struct Inner {}
1702 $0
1703}
1704 "#,
1705 "Inner",
1706 expect![[r#"
1707 Plain (imports ✔): Inner
1708 Plain (imports ✖): Inner
1709 ByCrate(imports ✔): Inner
1710 ByCrate(imports ✖): Inner
1711 BySelf (imports ✔): Inner
1712 BySelf (imports ✖): Inner
1713 "#]],
1714 );
1715 }
1716
1717 #[test]
1718 fn inner_items_from_outer_scope() {
1719 check_found_path(
1720 r#"
1721fn main() {
1722 struct Struct {}
1723 {
1724 $0
1725 }
1726}
1727 "#,
1728 "Struct",
1729 expect![[r#"
1730 Plain (imports ✔): Struct
1731 Plain (imports ✖): Struct
1732 ByCrate(imports ✔): Struct
1733 ByCrate(imports ✖): Struct
1734 BySelf (imports ✔): Struct
1735 BySelf (imports ✖): Struct
1736 "#]],
1737 );
1738 }
1739
1740 #[test]
1741 fn inner_items_from_inner_module() {
1742 check_found_path(
1743 r#"
1744fn main() {
1745 mod module {
1746 pub struct Struct {}
1747 }
1748 {
1749 $0
1750 }
1751}
1752 "#,
1753 "module::Struct",
1754 expect![[r#"
1755 Plain (imports ✔): module::Struct
1756 Plain (imports ✖): module::Struct
1757 ByCrate(imports ✔): module::Struct
1758 ByCrate(imports ✖): module::Struct
1759 BySelf (imports ✔): module::Struct
1760 BySelf (imports ✖): module::Struct
1761 "#]],
1762 );
1763 }
1764
1765 #[test]
1766 fn outer_items_with_inner_items_present() {
1767 check_found_path(
1768 r#"
1769mod module {
1770 pub struct CompleteMe;
1771}
1772
1773fn main() {
1774 fn inner() {}
1775 $0
1776}
1777 "#,
1778 "module::CompleteMe",
1779 expect![[r#"
1780 Plain (imports ✔): module::CompleteMe
1781 Plain (imports ✖): module::CompleteMe
1782 ByCrate(imports ✔): crate::module::CompleteMe
1783 ByCrate(imports ✖): crate::module::CompleteMe
1784 BySelf (imports ✔): self::module::CompleteMe
1785 BySelf (imports ✖): self::module::CompleteMe
1786 "#]],
1787 )
1788 }
1789
1790 #[test]
1791 fn from_inside_module() {
1792 check_found_path(
1793 r#"
1794mod baz {
1795 pub struct Foo {}
1796}
1797
1798mod bar {
1799 fn bar() {
1800 $0
1801 }
1802}
1803 "#,
1804 "crate::baz::Foo",
1805 expect![[r#"
1806 Plain (imports ✔): crate::baz::Foo
1807 Plain (imports ✖): crate::baz::Foo
1808 ByCrate(imports ✔): crate::baz::Foo
1809 ByCrate(imports ✖): crate::baz::Foo
1810 BySelf (imports ✔): crate::baz::Foo
1811 BySelf (imports ✖): crate::baz::Foo
1812 "#]],
1813 )
1814 }
1815
1816 #[test]
1817 fn from_inside_module2() {
1818 check_found_path(
1819 r#"
1820mod qux {
1821 pub mod baz {
1822 pub struct Foo {}
1823 }
1824
1825 mod bar {
1826 fn bar() {
1827 $0;
1828 }
1829 }
1830}
1831
1832 "#,
1833 "crate::qux::baz::Foo",
1834 expect![[r#"
1835 Plain (imports ✔): super::baz::Foo
1836 Plain (imports ✖): super::baz::Foo
1837 ByCrate(imports ✔): crate::qux::baz::Foo
1838 ByCrate(imports ✖): crate::qux::baz::Foo
1839 BySelf (imports ✔): super::baz::Foo
1840 BySelf (imports ✖): super::baz::Foo
1841 "#]],
1842 )
1843 }
1844
1845 #[test]
1846 fn from_inside_module_with_inner_items() {
1847 check_found_path(
1848 r#"
1849mod baz {
1850 pub struct Foo {}
1851}
1852
1853mod bar {
1854 fn bar() {
1855 fn inner() {}
1856 $0
1857 }
1858}
1859 "#,
1860 "crate::baz::Foo",
1861 expect![[r#"
1862 Plain (imports ✔): crate::baz::Foo
1863 Plain (imports ✖): crate::baz::Foo
1864 ByCrate(imports ✔): crate::baz::Foo
1865 ByCrate(imports ✖): crate::baz::Foo
1866 BySelf (imports ✔): crate::baz::Foo
1867 BySelf (imports ✖): crate::baz::Foo
1868 "#]],
1869 )
1870 }
1871
1872 #[test]
1873 fn recursive_pub_mod_reexport() {
1874 check_found_path(
1875 r#"
1876fn main() {
1877 let _ = 22_i32.as_name$0();
1878}
1879
1880pub mod name {
1881 pub trait AsName {
1882 fn as_name(&self) -> String;
1883 }
1884 impl AsName for i32 {
1885 fn as_name(&self) -> String {
1886 format!("Name: {}", self)
1887 }
1888 }
1889 pub use crate::name;
1890}
1891"#,
1892 "name::AsName",
1893 expect![[r#"
1894 Plain (imports ✔): name::AsName
1895 Plain (imports ✖): name::AsName
1896 ByCrate(imports ✔): crate::name::AsName
1897 ByCrate(imports ✖): crate::name::AsName
1898 BySelf (imports ✔): self::name::AsName
1899 BySelf (imports ✖): self::name::AsName
1900 "#]],
1901 );
1902 }
1903
1904 #[test]
1905 fn extern_crate() {
1906 check_found_path(
1907 r#"
1908//- /main.rs crate:main deps:dep
1909$0
1910//- /dep.rs crate:dep
1911"#,
1912 "dep",
1913 expect![[r#"
1914 Plain (imports ✔): dep
1915 Plain (imports ✖): dep
1916 ByCrate(imports ✔): dep
1917 ByCrate(imports ✖): dep
1918 BySelf (imports ✔): dep
1919 BySelf (imports ✖): dep
1920 "#]],
1921 );
1922
1923 check_found_path(
1924 r#"
1925//- /main.rs crate:main deps:dep
1926fn f() {
1927 fn inner() {}
1928 $0
1929}
1930//- /dep.rs crate:dep
1931"#,
1932 "dep",
1933 expect![[r#"
1934 Plain (imports ✔): dep
1935 Plain (imports ✖): dep
1936 ByCrate(imports ✔): dep
1937 ByCrate(imports ✖): dep
1938 BySelf (imports ✔): dep
1939 BySelf (imports ✖): dep
1940 "#]],
1941 );
1942 }
1943
1944 #[test]
1945 fn prelude_with_inner_items() {
1946 check_found_path(
1947 r#"
1948//- /main.rs edition:2018 crate:main deps:std
1949fn f() {
1950 fn inner() {}
1951 $0
1952}
1953//- /std.rs crate:std
1954pub mod prelude {
1955 pub mod rust_2018 {
1956 pub enum Option { None }
1957 pub use Option::*;
1958 }
1959}
1960 "#,
1961 "None",
1962 expect![[r#"
1963 Plain (imports ✔): None
1964 Plain (imports ✖): None
1965 ByCrate(imports ✔): None
1966 ByCrate(imports ✖): None
1967 BySelf (imports ✔): None
1968 BySelf (imports ✖): None
1969 "#]],
1970 );
1971 }
1972
1973 #[test]
1974 fn different_crate_renamed_through_dep() {
1975 check_found_path(
1976 r#"
1977//- /main.rs crate:main deps:intermediate
1978$0
1979//- /intermediate.rs crate:intermediate deps:std
1980pub extern crate std as std_renamed;
1981//- /std.rs crate:std
1982pub struct S;
1983 "#,
1984 "intermediate::std_renamed::S",
1985 expect![[r#"
1986 Plain (imports ✔): intermediate::std_renamed::S
1987 Plain (imports ✖): intermediate::std_renamed::S
1988 ByCrate(imports ✔): intermediate::std_renamed::S
1989 ByCrate(imports ✖): intermediate::std_renamed::S
1990 BySelf (imports ✔): intermediate::std_renamed::S
1991 BySelf (imports ✖): intermediate::std_renamed::S
1992 "#]],
1993 );
1994 }
1995
1996 #[test]
1997 fn different_crate_doc_hidden() {
1998 check_found_path(
1999 r#"
2000//- /main.rs crate:main deps:intermediate
2001$0
2002//- /intermediate.rs crate:intermediate deps:std
2003#[doc(hidden)]
2004pub extern crate std;
2005pub extern crate std as longer;
2006//- /std.rs crate:std
2007pub struct S;
2008 "#,
2009 "intermediate::longer::S",
2010 expect![[r#"
2011 Plain (imports ✔): intermediate::longer::S
2012 Plain (imports ✖): intermediate::longer::S
2013 ByCrate(imports ✔): intermediate::longer::S
2014 ByCrate(imports ✖): intermediate::longer::S
2015 BySelf (imports ✔): intermediate::longer::S
2016 BySelf (imports ✖): intermediate::longer::S
2017 "#]],
2018 );
2019 }
2020
2021 #[test]
2022 fn respect_doc_hidden() {
2023 check_found_path(
2024 r#"
2025//- /main.rs crate:main deps:std,lazy_static
2026$0
2027//- /lazy_static.rs crate:lazy_static deps:core
2028#[doc(hidden)]
2029pub use core::ops::Deref as __Deref;
2030//- /std.rs crate:std deps:core
2031pub use core::ops;
2032//- /core.rs crate:core
2033pub mod ops {
2034 pub trait Deref {}
2035}
2036 "#,
2037 "std::ops::Deref",
2038 expect![[r#"
2039 Plain (imports ✔): std::ops::Deref
2040 Plain (imports ✖): std::ops::Deref
2041 ByCrate(imports ✔): std::ops::Deref
2042 ByCrate(imports ✖): std::ops::Deref
2043 BySelf (imports ✔): std::ops::Deref
2044 BySelf (imports ✖): std::ops::Deref
2045 "#]],
2046 );
2047 }
2048
2049 #[test]
2050 fn respect_unstable_modules() {
2051 check_found_path_prefer_no_std_allow_unstable(
2052 r#"
2053//- /main.rs crate:main deps:std,core
2054extern crate std;
2055$0
2056//- /longer.rs crate:std deps:core
2057pub mod error {
2058 pub use core::error::Error;
2059}
2060//- /core.rs crate:core
2061pub mod error {
2062 #![unstable(feature = "error_in_core", issue = "103765")]
2063 pub trait Error {}
2064}
2065"#,
2066 "std::error::Error",
2067 expect![[r#"
2068 Plain (imports ✔): std::error::Error
2069 Plain (imports ✖): std::error::Error
2070 ByCrate(imports ✔): std::error::Error
2071 ByCrate(imports ✖): std::error::Error
2072 BySelf (imports ✔): std::error::Error
2073 BySelf (imports ✖): std::error::Error
2074 "#]],
2075 );
2076 }
2077
2078 #[test]
2079 fn respects_prelude_setting() {
2080 let ra_fixture = r#"
2081//- /main.rs crate:main deps:krate
2082$0
2083//- /krate.rs crate:krate
2084pub mod prelude {
2085 pub use crate::foo::*;
2086}
2087
2088pub mod foo {
2089 pub struct Foo;
2090}
2091"#;
2092 check_found_path(
2093 ra_fixture,
2094 "krate::foo::Foo",
2095 expect![[r#"
2096 Plain (imports ✔): krate::foo::Foo
2097 Plain (imports ✖): krate::foo::Foo
2098 ByCrate(imports ✔): krate::foo::Foo
2099 ByCrate(imports ✖): krate::foo::Foo
2100 BySelf (imports ✔): krate::foo::Foo
2101 BySelf (imports ✖): krate::foo::Foo
2102 "#]],
2103 );
2104 check_found_path_prelude(
2105 ra_fixture,
2106 "krate::prelude::Foo",
2107 expect![[r#"
2108 Plain (imports ✔): krate::prelude::Foo
2109 Plain (imports ✖): krate::prelude::Foo
2110 ByCrate(imports ✔): krate::prelude::Foo
2111 ByCrate(imports ✖): krate::prelude::Foo
2112 BySelf (imports ✔): krate::prelude::Foo
2113 BySelf (imports ✖): krate::prelude::Foo
2114 "#]],
2115 );
2116 }
2117
2118 #[test]
2119 fn avoids_prelude_when_prefer_prelude_false() {
2120 let ra_fixture = r#"
2121//- /main.rs crate:main deps:krate
2122$0
2123//- /krate.rs crate:krate
2124pub mod prelude {
2125 pub use crate::module::sub::*;
2126}
2127pub mod module {
2128 pub mod sub {
2129 pub struct Foo;
2130 }
2131}
2132"#;
2133 check_found_path(
2136 ra_fixture,
2137 "krate::module::sub::Foo",
2138 expect![[r#"
2139 Plain (imports ✔): krate::module::sub::Foo
2140 Plain (imports ✖): krate::module::sub::Foo
2141 ByCrate(imports ✔): krate::module::sub::Foo
2142 ByCrate(imports ✖): krate::module::sub::Foo
2143 BySelf (imports ✔): krate::module::sub::Foo
2144 BySelf (imports ✖): krate::module::sub::Foo
2145 "#]],
2146 );
2147 check_found_path_prelude(
2149 ra_fixture,
2150 "krate::prelude::Foo",
2151 expect![[r#"
2152 Plain (imports ✔): krate::prelude::Foo
2153 Plain (imports ✖): krate::prelude::Foo
2154 ByCrate(imports ✔): krate::prelude::Foo
2155 ByCrate(imports ✖): krate::prelude::Foo
2156 BySelf (imports ✔): krate::prelude::Foo
2157 BySelf (imports ✖): krate::prelude::Foo
2158 "#]],
2159 );
2160 }
2161
2162 #[test]
2163 fn respects_absolute_setting() {
2164 let ra_fixture = r#"
2165//- /main.rs crate:main deps:krate
2166$0
2167//- /krate.rs crate:krate
2168pub mod foo {
2169 pub struct Foo;
2170}
2171"#;
2172 check_found_path(
2173 ra_fixture,
2174 "krate::foo::Foo",
2175 expect![[r#"
2176 Plain (imports ✔): krate::foo::Foo
2177 Plain (imports ✖): krate::foo::Foo
2178 ByCrate(imports ✔): krate::foo::Foo
2179 ByCrate(imports ✖): krate::foo::Foo
2180 BySelf (imports ✔): krate::foo::Foo
2181 BySelf (imports ✖): krate::foo::Foo
2182 "#]],
2183 );
2184
2185 check_found_path_absolute(
2186 ra_fixture,
2187 "krate::foo::Foo",
2188 expect![[r#"
2189 Plain (imports ✔): ::krate::foo::Foo
2190 Plain (imports ✖): ::krate::foo::Foo
2191 ByCrate(imports ✔): ::krate::foo::Foo
2192 ByCrate(imports ✖): ::krate::foo::Foo
2193 BySelf (imports ✔): ::krate::foo::Foo
2194 BySelf (imports ✖): ::krate::foo::Foo
2195 "#]],
2196 );
2197 }
2198
2199 #[test]
2200 fn respect_segment_length() {
2201 check_found_path(
2202 r#"
2203//- /main.rs crate:main deps:petgraph
2204$0
2205//- /petgraph.rs crate:petgraph
2206pub mod graph {
2207 pub use crate::graph_impl::{
2208 NodeIndex
2209 };
2210}
2211
2212mod graph_impl {
2213 pub struct NodeIndex<Ix>(Ix);
2214}
2215
2216pub mod stable_graph {
2217 #[doc(no_inline)]
2218 pub use crate::graph::{NodeIndex};
2219}
2220
2221pub mod prelude {
2222 #[doc(no_inline)]
2223 pub use crate::graph::{NodeIndex};
2224}
2225"#,
2226 "petgraph::graph::NodeIndex",
2227 expect![[r#"
2228 Plain (imports ✔): petgraph::graph::NodeIndex
2229 Plain (imports ✖): petgraph::graph::NodeIndex
2230 ByCrate(imports ✔): petgraph::graph::NodeIndex
2231 ByCrate(imports ✖): petgraph::graph::NodeIndex
2232 BySelf (imports ✔): petgraph::graph::NodeIndex
2233 BySelf (imports ✖): petgraph::graph::NodeIndex
2234 "#]],
2235 );
2236 }
2237
2238 #[test]
2239 fn regression_17271() {
2240 check_found_path(
2241 r#"
2242//- /lib.rs crate:main
2243mod foo;
2244
2245//- /foo.rs
2246mod bar;
2247
2248pub fn b() {$0}
2249//- /foo/bar.rs
2250pub fn c() {}
2251"#,
2252 "bar::c",
2253 expect![[r#"
2254 Plain (imports ✔): bar::c
2255 Plain (imports ✖): bar::c
2256 ByCrate(imports ✔): crate::foo::bar::c
2257 ByCrate(imports ✖): crate::foo::bar::c
2258 BySelf (imports ✔): self::bar::c
2259 BySelf (imports ✖): self::bar::c
2260 "#]],
2261 );
2262 }
2263
2264 #[test]
2265 fn prefer_long_std_over_short_extern() {
2266 check_found_path(
2267 r#"
2268//- /lib.rs crate:main deps:futures_lite,std,core
2269$0
2270//- /futures_lite.rs crate:futures_lite deps:std,core
2271pub use crate::future::Future;
2272pub mod future {
2273 pub use core::future::Future;
2274}
2275//- /std.rs crate:std deps:core
2276pub use core::future;
2277//- /core.rs crate:core
2278pub mod future {
2279 pub trait Future {}
2280}
2281"#,
2282 "core::future::Future",
2283 expect![[r#"
2284 Plain (imports ✔): std::future::Future
2285 Plain (imports ✖): std::future::Future
2286 ByCrate(imports ✔): std::future::Future
2287 ByCrate(imports ✖): std::future::Future
2288 BySelf (imports ✔): std::future::Future
2289 BySelf (imports ✖): std::future::Future
2290 "#]],
2291 );
2292 }
2293}