Skip to main content

hir_def/
find_path.rs

1//! An algorithm to find a path to refer to a certain item.
2
3use 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    /// If true, prefer to unconditionally use imports of the `core` and `alloc` crate
26    /// over the std.
27    pub prefer_no_std: bool,
28    /// If true, prefer import paths containing a prelude module.
29    pub prefer_prelude: bool,
30    /// If true, prefer abs path (starting with `::`) where it is available.
31    pub prefer_absolute: bool,
32    /// If true, paths containing `#[unstable]` segments may be returned, but only if if there is no
33    /// stable path. This does not check, whether the item itself that is being imported is `#[unstable]`.
34    pub allow_unstable: bool,
35}
36
37/// Find a path that can be used to refer to a certain item. This can depend on
38/// *from where* you're referring to the item, hence the `from` parameter.
39pub 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 the item is a builtin, it's in scope
50    if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
51        return Some(ModPath::from_segments(PathKind::Plain, iter::once(builtin.as_name())));
52    }
53
54    // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
55    // default to plain paths.
56    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    /// Causes paths to always start with either `self`, `super`, `crate` or a crate-name.
98    /// This is the same as plain, just that paths will start with `self` prepended if the path
99    /// starts with an identifier that is not a crate.
100    BySelf,
101    /// Causes paths to not use a self, super or crate prefix.
102    Plain,
103    /// Causes paths to start with `crate` where applicable, effectively forcing paths to be absolute.
104    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
131/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleIdLt<'_>
132fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option<ModPath> {
133    // - if the item is a module, jump straight to module search
134    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        // - if the item is already in scope, return the name under which it is
147        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 the item is in the prelude, return the name from there
155    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        // - if the item is an enum variant, refer to it via the enum
161        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        // If this doesn't work, it seems we have no way of referring to the
167        // enum; that's very weird, but there might still be a reexport of the
168        // variant somewhere
169    }
170
171    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        // recursive base case, we can't find a path of length 0
186        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            // - if the item is the crate root, return `crate`
192            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        // - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude
200
201        let root_local_def_map = ctx.crate_root.local_def_map(ctx.db).1;
202        // rev here so we prefer looking at renamed extern decls first
203        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            // - if the item is already in scope, return the name under which it is
242            return Some(Choice::new(ctx.prefix.path_kind(), scope_name, Stable));
243        }
244    }
245
246    // - if the module can be referenced as self, super or crate, do that
247    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    // - if the module is in the prelude, return it by that path
259    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    // FIXME: We could have multiple applicable names here, but we currently only return the first
280    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
287/// Returns single-segment path (i.e. without any prefix) if `item` is found in prelude and its
288/// name doesn't clash in current scope.
289fn 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    // Check if the name is in current scope and it points to the same def.
304    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        // - if the item is the module we're in, use `self`
333        Some(PathKind::SELF)
334    } else if let Some(parent_id) = def_map[from].parent {
335        if item == parent_id {
336            // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
337            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        // we ran out of fuel, so we stop searching here
357        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        // Item was defined in the same crate that wants to import it. It cannot be found in any
368        // dependency in this case.
369        calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice)
370    } else if ctx.is_std_item {
371        // The item we are searching for comes from the sysroot libraries, so skip prefer looking in
372        // the sysroot libraries directly.
373        // We do need to fallback as the item in question could be re-exported by another crate
374        // while not being a transitive dependency of the current crate.
375        find_in_sysroot(ctx, visited_modules, item, max_len, best_choice)
376    } else {
377        // Item was defined in some upstream crate. This means that it must be exported from one,
378        // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
379        // that wants to import it here, but we always prefer to use the external path here.
380
381        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            // the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
456            continue;
457        }
458
459        // Determine best path for containing module and append last segment from `info`.
460        // FIXME: we should guide this to look up the path locally, or from the same crate again?
461        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                // the item is unstable and we are not allowed to use unstable items
469                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    // FIXME: cache the `find_local_import_locations` output?
486    find_local_import_locations(ctx, item, visited_modules, |visited_modules, name, module_id| {
487        // The container path may be at most `max_len - 1` segments since we push
488        // `name` on top of it.
489        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    /// The length in characters of the path
501    path_text_len: usize,
502    /// The stability of the path
503    stability: Stability,
504    /// Whether any segment of this path is named `prelude`
505    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(&current.stability)
538            .then_with(|| {
539                if prefer_prelude {
540                    other.has_prelude_segment.cmp(&current.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
576/// Finds locations in `from.krate` from which `item` can be imported by `from`.
577fn 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    // `from` can import anything below `from` with visibility of at least `from`, and anything
587    // above `from` with any visibility. That means we do not need to descend into private siblings
588    // of `from` (and similar).
589
590    // Compute the initial worklist. We start with all direct child modules of `from` as well as all
591    // of its (recursive) parent modules.
592    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            // already processed this module
609            continue;
610        }
611        *processed = true;
612        let data = if module.block(db).is_some() {
613            // Re-query the block's DefMap
614            block_def_map = module.def_map(db);
615            &block_def_map[module]
616        } else {
617            // Reuse the root DefMap
618            &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            // Ignore private imports unless they are explicit. these could be used if we are
638            // in a submodule of this module, but that's usually not
639            // what the user wants; and if this module can import
640            // the item and we're a submodule of it, so can we.
641            // Also this keeps the cached data smaller.
642            if declared || is_pub_or_explicit {
643                cb(visited_modules, name, module);
644            }
645        }
646
647        // Descend into all modules visible from `from`.
648        for (module, vis) in data.scope.modules_in_scope() {
649            if module.krate(db) != ctx.from.krate(db) {
650                // We don't need to look at modules from other crates as our item has to be in the
651                // current crate
652                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    /// `code` needs to contain a cursor marker; checks that `find_path` for the
684    /// item the `path` refers to returns that same path when called from the
685    /// module the cursor is in.
686    #[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        // Tests that short paths are used even for external items, when parts of the path are
986        // already in scope.
987        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        // Similar to partially_imported test case above, but with prefer_absolute enabled.
1040        // Even if the actual imported item is in external crate, if the path to that item
1041        // is starting from the imported name, then the path should not start from "::".
1042        // i.e. The first line in the expected output should not start from "::".
1043        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::S would be shorter, but using private imports seems wrong
1291            "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        // Should also work (on a best-effort basis) if `no_std` is conditionally enabled.
1500        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        // Should also work (on a best-effort basis) if `no_std` is conditionally disabled.
1531        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        // krate::prelude::Foo (3 segs) is shorter than krate::module::sub::Foo (4 segs),
2134        // but prefer_prelude=false should pick the longer canonical path.
2135        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        // prefer_prelude=true should still pick the shorter prelude path.
2148        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}