Skip to content

Commit 5fcf528

Browse files
committed
Auto merge of #15871 - Veykril:import-map, r=Veykril
Add config for preferring / ignoring prelude modules in find_path
2 parents 11a87c9 + 74e5444 commit 5fcf528

38 files changed

+403
-180
lines changed

crates/hir-def/src/find_path.rs

+127-46
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ pub fn find_path(
2121
item: ItemInNs,
2222
from: ModuleId,
2323
prefer_no_std: bool,
24+
prefer_prelude: bool,
2425
) -> Option<ModPath> {
2526
let _p = profile::span("find_path");
26-
find_path_inner(db, item, from, None, prefer_no_std)
27+
find_path_inner(db, item, from, None, prefer_no_std, prefer_prelude)
2728
}
2829

2930
pub fn find_path_prefixed(
@@ -32,9 +33,10 @@ pub fn find_path_prefixed(
3233
from: ModuleId,
3334
prefix_kind: PrefixKind,
3435
prefer_no_std: bool,
36+
prefer_prelude: bool,
3537
) -> Option<ModPath> {
3638
let _p = profile::span("find_path_prefixed");
37-
find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std)
39+
find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std, prefer_prelude)
3840
}
3941

4042
#[derive(Copy, Clone, Debug)]
@@ -88,6 +90,7 @@ fn find_path_inner(
8890
from: ModuleId,
8991
prefixed: Option<PrefixKind>,
9092
prefer_no_std: bool,
93+
prefer_prelude: bool,
9194
) -> Option<ModPath> {
9295
// - if the item is a builtin, it's in scope
9396
if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item {
@@ -109,6 +112,7 @@ fn find_path_inner(
109112
MAX_PATH_LEN,
110113
prefixed,
111114
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
115+
prefer_prelude,
112116
)
113117
.map(|(item, _)| item);
114118
}
@@ -134,6 +138,7 @@ fn find_path_inner(
134138
from,
135139
prefixed,
136140
prefer_no_std,
141+
prefer_prelude,
137142
) {
138143
let data = db.enum_data(variant.parent);
139144
path.push_segment(data.variants[variant.local_id].name.clone());
@@ -156,6 +161,7 @@ fn find_path_inner(
156161
from,
157162
prefixed,
158163
prefer_no_std || db.crate_supports_no_std(crate_root.krate),
164+
prefer_prelude,
159165
scope_name,
160166
)
161167
.map(|(item, _)| item)
@@ -171,6 +177,7 @@ fn find_path_for_module(
171177
max_len: usize,
172178
prefixed: Option<PrefixKind>,
173179
prefer_no_std: bool,
180+
prefer_prelude: bool,
174181
) -> Option<(ModPath, Stability)> {
175182
if max_len == 0 {
176183
return None;
@@ -236,6 +243,7 @@ fn find_path_for_module(
236243
from,
237244
prefixed,
238245
prefer_no_std,
246+
prefer_prelude,
239247
scope_name,
240248
)
241249
}
@@ -316,6 +324,7 @@ fn calculate_best_path(
316324
from: ModuleId,
317325
mut prefixed: Option<PrefixKind>,
318326
prefer_no_std: bool,
327+
prefer_prelude: bool,
319328
scope_name: Option<Name>,
320329
) -> Option<(ModPath, Stability)> {
321330
if max_len <= 1 {
@@ -351,11 +360,14 @@ fn calculate_best_path(
351360
best_path_len - 1,
352361
prefixed,
353362
prefer_no_std,
363+
prefer_prelude,
354364
) {
355365
path.0.push_segment(name);
356366

357367
let new_path = match best_path.take() {
358-
Some(best_path) => select_best_path(best_path, path, prefer_no_std),
368+
Some(best_path) => {
369+
select_best_path(best_path, path, prefer_no_std, prefer_prelude)
370+
}
359371
None => path,
360372
};
361373
best_path_len = new_path.0.len();
@@ -367,18 +379,18 @@ fn calculate_best_path(
367379
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
368380
// that wants to import it here, but we always prefer to use the external path here.
369381

370-
let crate_graph = db.crate_graph();
371-
let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| {
382+
for dep in &db.crate_graph()[from.krate].dependencies {
372383
let import_map = db.import_map(dep.crate_id);
373-
import_map.import_info_for(item).and_then(|info| {
384+
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
385+
for info in import_info_for {
374386
if info.is_doc_hidden {
375387
// the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
376-
return None;
388+
continue;
377389
}
378390

379391
// Determine best path for containing module and append last segment from `info`.
380392
// FIXME: we should guide this to look up the path locally, or from the same crate again?
381-
let (mut path, path_stability) = find_path_for_module(
393+
let Some((mut path, path_stability)) = find_path_for_module(
382394
db,
383395
def_map,
384396
visited_modules,
@@ -388,22 +400,26 @@ fn calculate_best_path(
388400
max_len - 1,
389401
prefixed,
390402
prefer_no_std,
391-
)?;
403+
prefer_prelude,
404+
) else {
405+
continue;
406+
};
392407
cov_mark::hit!(partially_imported);
393408
path.push_segment(info.name.clone());
394-
Some((
409+
410+
let path_with_stab = (
395411
path,
396412
zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }),
397-
))
398-
})
399-
});
413+
);
400414

401-
for path in extern_paths {
402-
let new_path = match best_path.take() {
403-
Some(best_path) => select_best_path(best_path, path, prefer_no_std),
404-
None => path,
405-
};
406-
update_best_path(&mut best_path, new_path);
415+
let new_path_with_stab = match best_path.take() {
416+
Some(best_path) => {
417+
select_best_path(best_path, path_with_stab, prefer_no_std, prefer_prelude)
418+
}
419+
None => path_with_stab,
420+
};
421+
update_best_path(&mut best_path, new_path_with_stab);
422+
}
407423
}
408424
}
409425
if let Some(module) = item.module(db) {
@@ -420,17 +436,39 @@ fn calculate_best_path(
420436
}
421437
}
422438

439+
/// Select the best (most relevant) path between two paths.
440+
/// This accounts for stability, path length whether std should be chosen over alloc/core paths as
441+
/// well as ignoring prelude like paths or not.
423442
fn select_best_path(
424-
old_path: (ModPath, Stability),
425-
new_path: (ModPath, Stability),
443+
old_path @ (_, old_stability): (ModPath, Stability),
444+
new_path @ (_, new_stability): (ModPath, Stability),
426445
prefer_no_std: bool,
446+
prefer_prelude: bool,
427447
) -> (ModPath, Stability) {
428-
match (old_path.1, new_path.1) {
448+
match (old_stability, new_stability) {
429449
(Stable, Unstable) => return old_path,
430450
(Unstable, Stable) => return new_path,
431451
_ => {}
432452
}
433453
const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc];
454+
455+
let choose = |new_path: (ModPath, _), old_path: (ModPath, _)| {
456+
let new_has_prelude = new_path.0.segments().iter().any(|seg| seg == &known::prelude);
457+
let old_has_prelude = old_path.0.segments().iter().any(|seg| seg == &known::prelude);
458+
match (new_has_prelude, old_has_prelude, prefer_prelude) {
459+
(true, false, true) | (false, true, false) => new_path,
460+
(true, false, false) | (false, true, true) => old_path,
461+
// no prelude difference in the paths, so pick the smaller one
462+
(true, true, _) | (false, false, _) => {
463+
if new_path.0.len() < old_path.0.len() {
464+
new_path
465+
} else {
466+
old_path
467+
}
468+
}
469+
}
470+
};
471+
434472
match (old_path.0.segments().first(), new_path.0.segments().first()) {
435473
(Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
436474
let rank = match prefer_no_std {
@@ -451,23 +489,11 @@ fn select_best_path(
451489
let orank = rank(old);
452490
match nrank.cmp(&orank) {
453491
Ordering::Less => old_path,
454-
Ordering::Equal => {
455-
if new_path.0.len() < old_path.0.len() {
456-
new_path
457-
} else {
458-
old_path
459-
}
460-
}
492+
Ordering::Equal => choose(new_path, old_path),
461493
Ordering::Greater => new_path,
462494
}
463495
}
464-
_ => {
465-
if new_path.0.len() < old_path.0.len() {
466-
new_path
467-
} else {
468-
old_path
469-
}
470-
}
496+
_ => choose(new_path, old_path),
471497
}
472498
}
473499

@@ -570,7 +596,13 @@ mod tests {
570596
/// `code` needs to contain a cursor marker; checks that `find_path` for the
571597
/// item the `path` refers to returns that same path when called from the
572598
/// module the cursor is in.
573-
fn check_found_path_(ra_fixture: &str, path: &str, prefix_kind: Option<PrefixKind>) {
599+
#[track_caller]
600+
fn check_found_path_(
601+
ra_fixture: &str,
602+
path: &str,
603+
prefix_kind: Option<PrefixKind>,
604+
prefer_prelude: bool,
605+
) {
574606
let (db, pos) = TestDB::with_position(ra_fixture);
575607
let module = db.module_at_position(pos);
576608
let parsed_path_file = syntax::SourceFile::parse(&format!("use {path};"));
@@ -589,11 +621,17 @@ mod tests {
589621
)
590622
.0
591623
.take_types()
592-
.unwrap();
593-
594-
let found_path =
595-
find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
596-
assert_eq!(found_path, Some(mod_path), "{prefix_kind:?}");
624+
.expect("path does not resolve to a type");
625+
626+
let found_path = find_path_inner(
627+
&db,
628+
ItemInNs::Types(resolved),
629+
module,
630+
prefix_kind,
631+
false,
632+
prefer_prelude,
633+
);
634+
assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}");
597635
}
598636

599637
fn check_found_path(
@@ -603,10 +641,23 @@ mod tests {
603641
absolute: &str,
604642
self_prefixed: &str,
605643
) {
606-
check_found_path_(ra_fixture, unprefixed, None);
607-
check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain));
608-
check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate));
609-
check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf));
644+
check_found_path_(ra_fixture, unprefixed, None, false);
645+
check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain), false);
646+
check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate), false);
647+
check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf), false);
648+
}
649+
650+
fn check_found_path_prelude(
651+
ra_fixture: &str,
652+
unprefixed: &str,
653+
prefixed: &str,
654+
absolute: &str,
655+
self_prefixed: &str,
656+
) {
657+
check_found_path_(ra_fixture, unprefixed, None, true);
658+
check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain), true);
659+
check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate), true);
660+
check_found_path_(ra_fixture, self_prefixed, Some(PrefixKind::BySelf), true);
610661
}
611662

612663
#[test]
@@ -1421,4 +1472,34 @@ pub mod error {
14211472
"std::error::Error",
14221473
);
14231474
}
1475+
1476+
#[test]
1477+
fn respects_prelude_setting() {
1478+
let ra_fixture = r#"
1479+
//- /main.rs crate:main deps:krate
1480+
$0
1481+
//- /krate.rs crate:krate
1482+
pub mod prelude {
1483+
pub use crate::foo::*;
1484+
}
1485+
1486+
pub mod foo {
1487+
pub struct Foo;
1488+
}
1489+
"#;
1490+
check_found_path(
1491+
ra_fixture,
1492+
"krate::foo::Foo",
1493+
"krate::foo::Foo",
1494+
"krate::foo::Foo",
1495+
"krate::foo::Foo",
1496+
);
1497+
check_found_path_prelude(
1498+
ra_fixture,
1499+
"krate::prelude::Foo",
1500+
"krate::prelude::Foo",
1501+
"krate::prelude::Foo",
1502+
"krate::prelude::Foo",
1503+
);
1504+
}
14241505
}

0 commit comments

Comments
 (0)