Skip to content

Commit cfdcaa7

Browse files
committed
Prefer standard library paths over shorter extern deps re-exports
1 parent 38814ec commit cfdcaa7

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

src/tools/rust-analyzer/crates/hir-def/src/find_path.rs

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! An algorithm to find a path to refer to a certain item.
22
3-
use std::{cell::Cell, cmp::Ordering, iter};
3+
use std::{cell::Cell, cmp::Ordering, iter, ops::BitOr};
44

5+
use base_db::CrateId;
56
use hir_expand::{
67
name::{AsName, Name},
78
Lookup,
@@ -37,7 +38,8 @@ pub fn find_path(
3738

3839
// within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
3940
// default to plain paths.
40-
if item.module(db).is_some_and(ModuleId::is_within_block) {
41+
let item_module = item.module(db)?;
42+
if item_module.is_within_block() {
4143
prefix_kind = PrefixKind::Plain;
4244
}
4345
cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate());
@@ -50,6 +52,7 @@ pub fn find_path(
5052
ignore_local_imports,
5153
from,
5254
from_def_map: &from.def_map(db),
55+
is_std_item: db.crate_graph()[item_module.krate()].origin.is_lang(),
5356
fuel: Cell::new(FIND_PATH_FUEL),
5457
},
5558
item,
@@ -104,6 +107,7 @@ struct FindPathCtx<'db> {
104107
ignore_local_imports: bool,
105108
from: ModuleId,
106109
from_def_map: &'db DefMap,
110+
is_std_item: bool,
107111
fuel: Cell<usize>,
108112
}
109113

@@ -373,9 +377,12 @@ fn calculate_best_path(
373377
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
374378
// that wants to import it here, but we always prefer to use the external path here.
375379

376-
for dep in &db.crate_graph()[ctx.from.krate].dependencies {
377-
let import_map = db.import_map(dep.crate_id);
378-
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
380+
let mut process_dep = |dep: CrateId| {
381+
let import_map = db.import_map(dep);
382+
let Some(import_info_for) = import_map.import_info_for(item) else {
383+
return false;
384+
};
385+
let mut processed_something = false;
379386
for info in import_info_for {
380387
if info.is_doc_hidden {
381388
// the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
@@ -396,8 +403,33 @@ fn calculate_best_path(
396403
);
397404

398405
process(path, info.name.clone(), &mut best_path_len);
406+
processed_something = true;
407+
}
408+
processed_something
409+
};
410+
411+
let dependencies = &db.crate_graph()[ctx.from.krate].dependencies;
412+
if ctx.is_std_item {
413+
// The item we are searching for comes from the sysroot libraries, so skip prefer looking in
414+
// the sysroot libraries directly.
415+
// We do need to fallback as the item in question could be re-exported by another crate
416+
// while not being a transitive dependency of the current crate.
417+
let processed = dependencies
418+
.iter()
419+
.filter(|it| it.is_sysroot())
420+
.map(|dep| process_dep(dep.crate_id))
421+
.reduce(BitOr::bitor)
422+
.unwrap_or(false);
423+
if processed {
424+
// Found a path in a sysroot crate, so return it.
425+
return best_path;
399426
}
400427
}
428+
429+
dependencies
430+
.iter()
431+
.filter(|it| !ctx.is_std_item || !it.is_sysroot())
432+
.for_each(|dep| _ = process_dep(dep.crate_id));
401433
}
402434
best_path
403435
}
@@ -1918,4 +1950,34 @@ pub fn c() {}
19181950
"#]],
19191951
);
19201952
}
1953+
1954+
#[test]
1955+
fn prefer_long_std_over_short_extern() {
1956+
check_found_path(
1957+
r#"
1958+
//- /lib.rs crate:main deps:futures_lite,std,core
1959+
$0
1960+
//- /futures_lite.rs crate:futures_lite deps:std,core
1961+
pub use crate::future::Future;
1962+
pub mod future {
1963+
pub use core::future::Future;
1964+
}
1965+
//- /std.rs crate:std deps:core
1966+
pub use core::future;
1967+
//- /core.rs crate:core
1968+
pub mod future {
1969+
pub trait Future {}
1970+
}
1971+
"#,
1972+
"core::future::Future",
1973+
expect![[r#"
1974+
Plain (imports ✔): std::future::Future
1975+
Plain (imports ✖): std::future::Future
1976+
ByCrate(imports ✔): std::future::Future
1977+
ByCrate(imports ✖): std::future::Future
1978+
BySelf (imports ✔): std::future::Future
1979+
BySelf (imports ✖): std::future::Future
1980+
"#]],
1981+
);
1982+
}
19211983
}

src/tools/rust-analyzer/crates/test-fixture/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,15 @@ impl ChangeFixture {
246246
for (from, to, prelude) in crate_deps {
247247
let from_id = crates[&from];
248248
let to_id = crates[&to];
249+
let sysroot = crate_graph[to_id].origin.is_lang();
249250
crate_graph
250251
.add_dep(
251252
from_id,
252253
Dependency::with_prelude(
253254
CrateName::new(&to).unwrap(),
254255
to_id,
255256
prelude,
256-
false,
257+
sysroot,
257258
),
258259
)
259260
.unwrap();

0 commit comments

Comments
 (0)