Skip to content

Commit ba61766

Browse files
committed
Add config for preferring / ignoring prelude modules in find_path
1 parent 801a887 commit ba61766

36 files changed

+261
-55
lines changed

crates/hir-def/src/find_path.rs

Lines changed: 110 additions & 30 deletions
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();
@@ -388,6 +400,7 @@ fn calculate_best_path(
388400
max_len - 1,
389401
prefixed,
390402
prefer_no_std,
403+
prefer_prelude,
391404
) else {
392405
continue;
393406
};
@@ -400,7 +413,9 @@ fn calculate_best_path(
400413
);
401414

402415
let new_path_with_stab = match best_path.take() {
403-
Some(best_path) => select_best_path(best_path, path_with_stab, prefer_no_std),
416+
Some(best_path) => {
417+
select_best_path(best_path, path_with_stab, prefer_no_std, prefer_prelude)
418+
}
404419
None => path_with_stab,
405420
};
406421
update_best_path(&mut best_path, new_path_with_stab);
@@ -421,17 +436,39 @@ fn calculate_best_path(
421436
}
422437
}
423438

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.
424442
fn select_best_path(
425-
old_path: (ModPath, Stability),
426-
new_path: (ModPath, Stability),
443+
old_path @ (_, old_stability): (ModPath, Stability),
444+
new_path @ (_, new_stability): (ModPath, Stability),
427445
prefer_no_std: bool,
446+
prefer_prelude: bool,
428447
) -> (ModPath, Stability) {
429-
match (old_path.1, new_path.1) {
448+
match (old_stability, new_stability) {
430449
(Stable, Unstable) => return old_path,
431450
(Unstable, Stable) => return new_path,
432451
_ => {}
433452
}
434453
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+
435472
match (old_path.0.segments().first(), new_path.0.segments().first()) {
436473
(Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => {
437474
let rank = match prefer_no_std {
@@ -452,23 +489,11 @@ fn select_best_path(
452489
let orank = rank(old);
453490
match nrank.cmp(&orank) {
454491
Ordering::Less => old_path,
455-
Ordering::Equal => {
456-
if new_path.0.len() < old_path.0.len() {
457-
new_path
458-
} else {
459-
old_path
460-
}
461-
}
492+
Ordering::Equal => choose(new_path, old_path),
462493
Ordering::Greater => new_path,
463494
}
464495
}
465-
_ => {
466-
if new_path.0.len() < old_path.0.len() {
467-
new_path
468-
} else {
469-
old_path
470-
}
471-
}
496+
_ => choose(new_path, old_path),
472497
}
473498
}
474499

@@ -571,7 +596,13 @@ mod tests {
571596
/// `code` needs to contain a cursor marker; checks that `find_path` for the
572597
/// item the `path` refers to returns that same path when called from the
573598
/// module the cursor is in.
574-
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+
) {
575606
let (db, pos) = TestDB::with_position(ra_fixture);
576607
let module = db.module_at_position(pos);
577608
let parsed_path_file = syntax::SourceFile::parse(&format!("use {path};"));
@@ -590,10 +621,16 @@ mod tests {
590621
)
591622
.0
592623
.take_types()
593-
.unwrap();
594-
595-
let found_path =
596-
find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
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+
);
597634
assert_eq!(found_path, Some(mod_path), "on kind: {prefix_kind:?}");
598635
}
599636

@@ -604,10 +641,23 @@ mod tests {
604641
absolute: &str,
605642
self_prefixed: &str,
606643
) {
607-
check_found_path_(ra_fixture, unprefixed, None);
608-
check_found_path_(ra_fixture, prefixed, Some(PrefixKind::Plain));
609-
check_found_path_(ra_fixture, absolute, Some(PrefixKind::ByCrate));
610-
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);
611661
}
612662

613663
#[test]
@@ -1422,4 +1472,34 @@ pub mod error {
14221472
"std::error::Error",
14231473
);
14241474
}
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+
}
14251505
}

crates/hir-ty/src/display.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,7 @@ impl HirDisplay for Ty {
945945
ItemInNs::Types((*def_id).into()),
946946
module_id,
947947
false,
948+
true,
948949
) {
949950
write!(f, "{}", path.display(f.db.upcast()))?;
950951
} else {

crates/hir/src/lib.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,8 +664,15 @@ impl Module {
664664
db: &dyn DefDatabase,
665665
item: impl Into<ItemInNs>,
666666
prefer_no_std: bool,
667+
prefer_prelude: bool,
667668
) -> Option<ModPath> {
668-
hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std)
669+
hir_def::find_path::find_path(
670+
db,
671+
item.into().into(),
672+
self.into(),
673+
prefer_no_std,
674+
prefer_prelude,
675+
)
669676
}
670677

671678
/// Finds a path that can be used to refer to the given item from within
@@ -676,13 +683,15 @@ impl Module {
676683
item: impl Into<ItemInNs>,
677684
prefix_kind: PrefixKind,
678685
prefer_no_std: bool,
686+
prefer_prelude: bool,
679687
) -> Option<ModPath> {
680688
hir_def::find_path::find_path_prefixed(
681689
db,
682690
item.into().into(),
683691
self.into(),
684692
prefix_kind,
685693
prefer_no_std,
694+
prefer_prelude,
686695
)
687696
}
688697
}

crates/ide-assists/src/assist_config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ pub struct AssistConfig {
1414
pub allowed: Option<Vec<AssistKind>>,
1515
pub insert_use: InsertUseConfig,
1616
pub prefer_no_std: bool,
17+
pub prefer_prelude: bool,
1718
pub assist_emit_must_use: bool,
1819
}

crates/ide-assists/src/handlers/add_missing_match_arms.rs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
8888
.into_iter()
8989
.filter_map(|variant| {
9090
Some((
91-
build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std)?,
91+
build_pat(
92+
ctx.db(),
93+
module,
94+
variant,
95+
ctx.config.prefer_no_std,
96+
ctx.config.prefer_prelude,
97+
)?,
9298
variant.should_be_hidden(ctx.db(), module.krate()),
9399
))
94100
})
@@ -140,7 +146,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
140146
.iter()
141147
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
142148
let patterns = variants.into_iter().filter_map(|variant| {
143-
build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std)
149+
build_pat(
150+
ctx.db(),
151+
module,
152+
variant,
153+
ctx.config.prefer_no_std,
154+
ctx.config.prefer_prelude,
155+
)
144156
});
145157

146158
(ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
@@ -173,7 +185,13 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
173185
.iter()
174186
.any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
175187
let patterns = variants.into_iter().filter_map(|variant| {
176-
build_pat(ctx.db(), module, variant.clone(), ctx.config.prefer_no_std)
188+
build_pat(
189+
ctx.db(),
190+
module,
191+
variant.clone(),
192+
ctx.config.prefer_no_std,
193+
ctx.config.prefer_prelude,
194+
)
177195
});
178196
(ast::Pat::from(make::slice_pat(patterns)), is_hidden)
179197
})
@@ -440,11 +458,16 @@ fn build_pat(
440458
module: hir::Module,
441459
var: ExtendedVariant,
442460
prefer_no_std: bool,
461+
prefer_prelude: bool,
443462
) -> Option<ast::Pat> {
444463
match var {
445464
ExtendedVariant::Variant(var) => {
446-
let path =
447-
mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_no_std)?);
465+
let path = mod_path_to_ast(&module.find_use_path(
466+
db,
467+
ModuleDef::from(var),
468+
prefer_no_std,
469+
prefer_prelude,
470+
)?);
448471

449472
// FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
450473
Some(match var.source(db)?.value.kind() {

0 commit comments

Comments
 (0)