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