Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 85 additions & 14 deletions crates/ra_hir_def/src/find_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,39 @@ use crate::{
visibility::Visibility,
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;

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

/// Find a path that can be used to refer to a certain item. This can depend on
Expand Down Expand Up @@ -112,23 +141,27 @@ fn find_path_inner(
Some(path) => path,
};
path.segments.push(name);
if path_len(&path) < best_path_len {
best_path_len = path_len(&path);
best_path = Some(path);
}

let new_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
}

fn path_len(path: &ModPath) -> usize {
path.segments.len()
+ match path.kind {
PathKind::Plain => 0,
PathKind::Super(i) => i as usize,
PathKind::Crate => 1,
PathKind::Abs => 0,
PathKind::DollarCrate(_) => 1,
}
fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath {
if old_path.starts_with_std() && new_path.should_start_with_std() {
tested_by!(prefer_std_paths);
old_path
} else if new_path.starts_with_std() && old_path.should_start_with_std() {
tested_by!(prefer_std_paths);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

new_path
} else if new_path.len() < old_path.len() {
new_path
} else {
old_path
}
}

fn find_importable_locations(
Expand Down Expand Up @@ -201,6 +234,7 @@ mod tests {
use hir_expand::hygiene::Hygiene;
use ra_db::fixture::WithFixture;
use ra_syntax::ast::AstNode;
use test_utils::covers;

/// `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
Expand Down Expand Up @@ -452,4 +486,41 @@ mod tests {
"#;
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");
}
}
1 change: 1 addition & 0 deletions crates/ra_hir_def/src/marks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ test_utils::marks!(
macro_dollar_crate_self
macro_dollar_crate_other
infer_resolve_while_let
prefer_std_paths
);
2 changes: 2 additions & 0 deletions crates/ra_hir_expand/src/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ pub mod known {
macro_rules,
// Components of known path (value or mod name)
std,
core,
alloc,
iter,
ops,
future,
Expand Down