mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 21:13:37 +00:00
Prefer standard library paths over shorter extern deps re-exports
This commit is contained in:
parent
41603ab14e
commit
40bbc684ad
2 changed files with 69 additions and 6 deletions
|
@ -1,7 +1,8 @@
|
|||
//! An algorithm to find a path to refer to a certain item.
|
||||
|
||||
use std::{cell::Cell, cmp::Ordering, iter};
|
||||
use std::{cell::Cell, cmp::Ordering, iter, ops::BitOr};
|
||||
|
||||
use base_db::CrateId;
|
||||
use hir_expand::{
|
||||
name::{AsName, Name},
|
||||
Lookup,
|
||||
|
@ -37,7 +38,8 @@ pub fn find_path(
|
|||
|
||||
// within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
|
||||
// default to plain paths.
|
||||
if item.module(db).is_some_and(ModuleId::is_within_block) {
|
||||
let item_module = item.module(db)?;
|
||||
if item_module.is_within_block() {
|
||||
prefix_kind = PrefixKind::Plain;
|
||||
}
|
||||
cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate());
|
||||
|
@ -50,6 +52,7 @@ pub fn find_path(
|
|||
ignore_local_imports,
|
||||
from,
|
||||
from_def_map: &from.def_map(db),
|
||||
is_std_item: db.crate_graph()[item_module.krate()].origin.is_lang(),
|
||||
fuel: Cell::new(FIND_PATH_FUEL),
|
||||
},
|
||||
item,
|
||||
|
@ -104,6 +107,7 @@ struct FindPathCtx<'db> {
|
|||
ignore_local_imports: bool,
|
||||
from: ModuleId,
|
||||
from_def_map: &'db DefMap,
|
||||
is_std_item: bool,
|
||||
fuel: Cell<usize>,
|
||||
}
|
||||
|
||||
|
@ -373,9 +377,12 @@ fn calculate_best_path(
|
|||
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
|
||||
// that wants to import it here, but we always prefer to use the external path here.
|
||||
|
||||
for dep in &db.crate_graph()[ctx.from.krate].dependencies {
|
||||
let import_map = db.import_map(dep.crate_id);
|
||||
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
|
||||
let mut process_dep = |dep: CrateId| {
|
||||
let import_map = db.import_map(dep);
|
||||
let Some(import_info_for) = import_map.import_info_for(item) else {
|
||||
return false;
|
||||
};
|
||||
let mut processed_something = false;
|
||||
for info in import_info_for {
|
||||
if info.is_doc_hidden {
|
||||
// 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(
|
|||
);
|
||||
|
||||
process(path, info.name.clone(), &mut best_path_len);
|
||||
processed_something = true;
|
||||
}
|
||||
processed_something
|
||||
};
|
||||
|
||||
let dependencies = &db.crate_graph()[ctx.from.krate].dependencies;
|
||||
if ctx.is_std_item {
|
||||
// The item we are searching for comes from the sysroot libraries, so skip prefer looking in
|
||||
// the sysroot libraries directly.
|
||||
// We do need to fallback as the item in question could be re-exported by another crate
|
||||
// while not being a transitive dependency of the current crate.
|
||||
let processed = dependencies
|
||||
.iter()
|
||||
.filter(|it| it.is_sysroot())
|
||||
.map(|dep| process_dep(dep.crate_id))
|
||||
.reduce(BitOr::bitor)
|
||||
.unwrap_or(false);
|
||||
if processed {
|
||||
// Found a path in a sysroot crate, so return it.
|
||||
return best_path;
|
||||
}
|
||||
}
|
||||
|
||||
dependencies
|
||||
.iter()
|
||||
.filter(|it| !ctx.is_std_item || !it.is_sysroot())
|
||||
.for_each(|dep| _ = process_dep(dep.crate_id));
|
||||
}
|
||||
best_path
|
||||
}
|
||||
|
@ -1918,4 +1950,34 @@ pub fn c() {}
|
|||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn prefer_long_std_over_short_extern() {
|
||||
check_found_path(
|
||||
r#"
|
||||
//- /lib.rs crate:main deps:futures_lite,std,core
|
||||
$0
|
||||
//- /futures_lite.rs crate:futures_lite deps:std,core
|
||||
pub use crate::future::Future;
|
||||
pub mod future {
|
||||
pub use core::future::Future;
|
||||
}
|
||||
//- /std.rs crate:std deps:core
|
||||
pub use core::future;
|
||||
//- /core.rs crate:core
|
||||
pub mod future {
|
||||
pub trait Future {}
|
||||
}
|
||||
"#,
|
||||
"core::future::Future",
|
||||
expect![[r#"
|
||||
Plain (imports ✔): std::future::Future
|
||||
Plain (imports ✖): std::future::Future
|
||||
ByCrate(imports ✔): std::future::Future
|
||||
ByCrate(imports ✖): std::future::Future
|
||||
BySelf (imports ✔): std::future::Future
|
||||
BySelf (imports ✖): std::future::Future
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,6 +246,7 @@ impl ChangeFixture {
|
|||
for (from, to, prelude) in crate_deps {
|
||||
let from_id = crates[&from];
|
||||
let to_id = crates[&to];
|
||||
let sysroot = crate_graph[to_id].origin.is_lang();
|
||||
crate_graph
|
||||
.add_dep(
|
||||
from_id,
|
||||
|
@ -253,7 +254,7 @@ impl ChangeFixture {
|
|||
CrateName::new(&to).unwrap(),
|
||||
to_id,
|
||||
prelude,
|
||||
false,
|
||||
sysroot,
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
|
Loading…
Reference in a new issue