Merge #2917
2917: Prefer imports starting with std r=matklad a=SomeoneToIgnore Closes https://github.com/rust-analyzer/rust-analyzer/issues/2915 Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
This commit is contained in:
commit
3bdf2e0972
@ -7,10 +7,39 @@
|
|||||||
visibility::Visibility,
|
visibility::Visibility,
|
||||||
CrateId, ModuleDefId, ModuleId,
|
CrateId, ModuleDefId, ModuleId,
|
||||||
};
|
};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::{known, Name};
|
||||||
|
use test_utils::tested_by;
|
||||||
|
|
||||||
const MAX_PATH_LEN: usize = 15;
|
const MAX_PATH_LEN: usize = 15;
|
||||||
|
|
||||||
|
impl ModPath {
|
||||||
|
fn starts_with_std(&self) -> bool {
|
||||||
|
self.segments.first().filter(|&first_segment| first_segment == &known::std).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
// When std library is present, paths starting with `std::`
|
||||||
|
// should be preferred over paths starting with `core::` and `alloc::`
|
||||||
|
fn should_start_with_std(&self) -> bool {
|
||||||
|
self.segments
|
||||||
|
.first()
|
||||||
|
.filter(|&first_segment| {
|
||||||
|
first_segment == &known::alloc || first_segment == &known::core
|
||||||
|
})
|
||||||
|
.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.segments.len()
|
||||||
|
+ match self.kind {
|
||||||
|
PathKind::Plain => 0,
|
||||||
|
PathKind::Super(i) => i as usize,
|
||||||
|
PathKind::Crate => 1,
|
||||||
|
PathKind::Abs => 0,
|
||||||
|
PathKind::DollarCrate(_) => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: handle local items
|
// FIXME: handle local items
|
||||||
|
|
||||||
/// Find a path that can be used to refer to a certain item. This can depend on
|
/// Find a path that can be used to refer to a certain item. This can depend on
|
||||||
@ -112,23 +141,27 @@ fn find_path_inner(
|
|||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
};
|
};
|
||||||
path.segments.push(name);
|
path.segments.push(name);
|
||||||
if path_len(&path) < best_path_len {
|
|
||||||
best_path_len = path_len(&path);
|
let new_path =
|
||||||
best_path = Some(path);
|
if let Some(best_path) = best_path { select_best_path(best_path, path) } else { path };
|
||||||
}
|
best_path_len = new_path.len();
|
||||||
|
best_path = Some(new_path);
|
||||||
}
|
}
|
||||||
best_path
|
best_path
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_len(path: &ModPath) -> usize {
|
fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath {
|
||||||
path.segments.len()
|
if old_path.starts_with_std() && new_path.should_start_with_std() {
|
||||||
+ match path.kind {
|
tested_by!(prefer_std_paths);
|
||||||
PathKind::Plain => 0,
|
old_path
|
||||||
PathKind::Super(i) => i as usize,
|
} else if new_path.starts_with_std() && old_path.should_start_with_std() {
|
||||||
PathKind::Crate => 1,
|
tested_by!(prefer_std_paths);
|
||||||
PathKind::Abs => 0,
|
new_path
|
||||||
PathKind::DollarCrate(_) => 1,
|
} else if new_path.len() < old_path.len() {
|
||||||
}
|
new_path
|
||||||
|
} else {
|
||||||
|
old_path
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_importable_locations(
|
fn find_importable_locations(
|
||||||
@ -201,6 +234,7 @@ mod tests {
|
|||||||
use hir_expand::hygiene::Hygiene;
|
use hir_expand::hygiene::Hygiene;
|
||||||
use ra_db::fixture::WithFixture;
|
use ra_db::fixture::WithFixture;
|
||||||
use ra_syntax::ast::AstNode;
|
use ra_syntax::ast::AstNode;
|
||||||
|
use test_utils::covers;
|
||||||
|
|
||||||
/// `code` needs to contain a cursor marker; checks that `find_path` for the
|
/// `code` needs to contain a cursor marker; checks that `find_path` for the
|
||||||
/// item the `path` refers to returns that same path when called from the
|
/// item the `path` refers to returns that same path when called from the
|
||||||
@ -452,4 +486,41 @@ fn import_cycle() {
|
|||||||
"#;
|
"#;
|
||||||
check_found_path(code, "crate::foo::S");
|
check_found_path(code, "crate::foo::S");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn prefer_std_paths_over_alloc() {
|
||||||
|
covers!(prefer_std_paths);
|
||||||
|
let code = r#"
|
||||||
|
//- /main.rs crate:main deps:alloc,std
|
||||||
|
<|>
|
||||||
|
|
||||||
|
//- /std.rs crate:std deps:alloc
|
||||||
|
pub mod sync {
|
||||||
|
pub use alloc::sync::Arc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /zzz.rs crate:alloc
|
||||||
|
pub mod sync {
|
||||||
|
pub struct Arc;
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
check_found_path(code, "std::sync::Arc");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn prefer_shorter_paths_if_not_alloc() {
|
||||||
|
let code = r#"
|
||||||
|
//- /main.rs crate:main deps:megaalloc,std
|
||||||
|
<|>
|
||||||
|
|
||||||
|
//- /std.rs crate:std deps:megaalloc
|
||||||
|
pub mod sync {
|
||||||
|
pub use megaalloc::sync::Arc;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- /zzz.rs crate:megaalloc
|
||||||
|
pub struct Arc;
|
||||||
|
"#;
|
||||||
|
check_found_path(code, "megaalloc::Arc");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,4 +13,5 @@
|
|||||||
macro_dollar_crate_self
|
macro_dollar_crate_self
|
||||||
macro_dollar_crate_other
|
macro_dollar_crate_other
|
||||||
infer_resolve_while_let
|
infer_resolve_while_let
|
||||||
|
prefer_std_paths
|
||||||
);
|
);
|
||||||
|
@ -141,6 +141,8 @@ macro_rules! known_names {
|
|||||||
macro_rules,
|
macro_rules,
|
||||||
// Components of known path (value or mod name)
|
// Components of known path (value or mod name)
|
||||||
std,
|
std,
|
||||||
|
core,
|
||||||
|
alloc,
|
||||||
iter,
|
iter,
|
||||||
ops,
|
ops,
|
||||||
future,
|
future,
|
||||||
|
Loading…
Reference in New Issue
Block a user