aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/find_path.rs99
-rw-r--r--crates/ra_hir_def/src/marks.rs1
-rw-r--r--crates/ra_hir_def/src/nameres.rs40
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs43
4 files changed, 128 insertions, 55 deletions
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs
index 8cc2fb160..43b9b124a 100644
--- a/crates/ra_hir_def/src/find_path.rs
+++ b/crates/ra_hir_def/src/find_path.rs
@@ -7,10 +7,39 @@ use crate::{
7 visibility::Visibility, 7 visibility::Visibility,
8 CrateId, ModuleDefId, ModuleId, 8 CrateId, ModuleDefId, ModuleId,
9}; 9};
10use hir_expand::name::Name; 10use hir_expand::name::{known, Name};
11use test_utils::tested_by;
11 12
12const MAX_PATH_LEN: usize = 15; 13const MAX_PATH_LEN: usize = 15;
13 14
15impl ModPath {
16 fn starts_with_std(&self) -> bool {
17 self.segments.first().filter(|&first_segment| first_segment == &known::std).is_some()
18 }
19
20 // When std library is present, paths starting with `std::`
21 // should be preferred over paths starting with `core::` and `alloc::`
22 fn should_start_with_std(&self) -> bool {
23 self.segments
24 .first()
25 .filter(|&first_segment| {
26 first_segment == &known::alloc || first_segment == &known::core
27 })
28 .is_some()
29 }
30
31 fn len(&self) -> usize {
32 self.segments.len()
33 + match self.kind {
34 PathKind::Plain => 0,
35 PathKind::Super(i) => i as usize,
36 PathKind::Crate => 1,
37 PathKind::Abs => 0,
38 PathKind::DollarCrate(_) => 1,
39 }
40 }
41}
42
14// FIXME: handle local items 43// FIXME: handle local items
15 44
16/// Find a path that can be used to refer to a certain item. This can depend on 45/// 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(
112 Some(path) => path, 141 Some(path) => path,
113 }; 142 };
114 path.segments.push(name); 143 path.segments.push(name);
115 if path_len(&path) < best_path_len { 144
116 best_path_len = path_len(&path); 145 let new_path =
117 best_path = Some(path); 146 if let Some(best_path) = best_path { select_best_path(best_path, path) } else { path };
118 } 147 best_path_len = new_path.len();
148 best_path = Some(new_path);
119 } 149 }
120 best_path 150 best_path
121} 151}
122 152
123fn path_len(path: &ModPath) -> usize { 153fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath {
124 path.segments.len() 154 if old_path.starts_with_std() && new_path.should_start_with_std() {
125 + match path.kind { 155 tested_by!(prefer_std_paths);
126 PathKind::Plain => 0, 156 old_path
127 PathKind::Super(i) => i as usize, 157 } else if new_path.starts_with_std() && old_path.should_start_with_std() {
128 PathKind::Crate => 1, 158 tested_by!(prefer_std_paths);
129 PathKind::Abs => 0, 159 new_path
130 PathKind::DollarCrate(_) => 1, 160 } else if new_path.len() < old_path.len() {
131 } 161 new_path
162 } else {
163 old_path
164 }
132} 165}
133 166
134fn find_importable_locations( 167fn find_importable_locations(
@@ -201,6 +234,7 @@ mod tests {
201 use hir_expand::hygiene::Hygiene; 234 use hir_expand::hygiene::Hygiene;
202 use ra_db::fixture::WithFixture; 235 use ra_db::fixture::WithFixture;
203 use ra_syntax::ast::AstNode; 236 use ra_syntax::ast::AstNode;
237 use test_utils::covers;
204 238
205 /// `code` needs to contain a cursor marker; checks that `find_path` for the 239 /// `code` needs to contain a cursor marker; checks that `find_path` for the
206 /// item the `path` refers to returns that same path when called from the 240 /// item the `path` refers to returns that same path when called from the
@@ -452,4 +486,41 @@ mod tests {
452 "#; 486 "#;
453 check_found_path(code, "crate::foo::S"); 487 check_found_path(code, "crate::foo::S");
454 } 488 }
489
490 #[test]
491 fn prefer_std_paths_over_alloc() {
492 covers!(prefer_std_paths);
493 let code = r#"
494 //- /main.rs crate:main deps:alloc,std
495 <|>
496
497 //- /std.rs crate:std deps:alloc
498 pub mod sync {
499 pub use alloc::sync::Arc;
500 }
501
502 //- /zzz.rs crate:alloc
503 pub mod sync {
504 pub struct Arc;
505 }
506 "#;
507 check_found_path(code, "std::sync::Arc");
508 }
509
510 #[test]
511 fn prefer_shorter_paths_if_not_alloc() {
512 let code = r#"
513 //- /main.rs crate:main deps:megaalloc,std
514 <|>
515
516 //- /std.rs crate:std deps:megaalloc
517 pub mod sync {
518 pub use megaalloc::sync::Arc;
519 }
520
521 //- /zzz.rs crate:megaalloc
522 pub struct Arc;
523 "#;
524 check_found_path(code, "megaalloc::Arc");
525 }
455} 526}
diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs
index 457ba4abe..daa49d5f1 100644
--- a/crates/ra_hir_def/src/marks.rs
+++ b/crates/ra_hir_def/src/marks.rs
@@ -13,4 +13,5 @@ test_utils::marks!(
13 macro_dollar_crate_self 13 macro_dollar_crate_self
14 macro_dollar_crate_other 14 macro_dollar_crate_other
15 infer_resolve_while_let 15 infer_resolve_while_let
16 prefer_std_paths
16); 17);
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 27c12e46c..852304dd0 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -229,6 +229,46 @@ impl CrateDefMap {
229 self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow); 229 self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
230 (res.resolved_def, res.segment_index) 230 (res.resolved_def, res.segment_index)
231 } 231 }
232
233 // FIXME: this can use some more human-readable format (ideally, an IR
234 // even), as this should be a great debugging aid.
235 pub fn dump(&self) -> String {
236 let mut buf = String::new();
237 go(&mut buf, self, "\ncrate", self.root);
238 return buf.trim().to_string();
239
240 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) {
241 *buf += path;
242 *buf += "\n";
243
244 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect();
245 entries.sort_by_key(|(name, _)| name.clone());
246
247 for (name, def) in entries {
248 *buf += &format!("{}:", name);
249
250 if def.types.is_some() {
251 *buf += " t";
252 }
253 if def.values.is_some() {
254 *buf += " v";
255 }
256 if def.macros.is_some() {
257 *buf += " m";
258 }
259 if def.is_none() {
260 *buf += " _";
261 }
262
263 *buf += "\n";
264 }
265
266 for (name, child) in map.modules[module].children.iter() {
267 let path = path.to_string() + &format!("::{}", name);
268 go(buf, map, &path, *child);
269 }
270 }
271 }
232} 272}
233 273
234impl ModuleData { 274impl ModuleData {
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 78bcdc850..82f0f835c 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -10,11 +10,10 @@ use insta::assert_snapshot;
10use ra_db::{fixture::WithFixture, SourceDatabase}; 10use ra_db::{fixture::WithFixture, SourceDatabase};
11use test_utils::covers; 11use test_utils::covers;
12 12
13use crate::{db::DefDatabase, nameres::*, test_db::TestDB, LocalModuleId}; 13use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
14 14
15fn def_map(fixture: &str) -> String { 15fn def_map(fixture: &str) -> String {
16 let dm = compute_crate_def_map(fixture); 16 compute_crate_def_map(fixture).dump()
17 render_crate_def_map(&dm)
18} 17}
19 18
20fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> { 19fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
@@ -23,44 +22,6 @@ fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
23 db.crate_def_map(krate) 22 db.crate_def_map(krate)
24} 23}
25 24
26fn render_crate_def_map(map: &CrateDefMap) -> String {
27 let mut buf = String::new();
28 go(&mut buf, map, "\ncrate", map.root);
29 return buf.trim().to_string();
30
31 fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: LocalModuleId) {
32 *buf += path;
33 *buf += "\n";
34
35 let mut entries: Vec<_> = map.modules[module].scope.resolutions().collect();
36 entries.sort_by_key(|(name, _)| name.clone());
37
38 for (name, def) in entries {
39 *buf += &format!("{}:", name);
40
41 if def.types.is_some() {
42 *buf += " t";
43 }
44 if def.values.is_some() {
45 *buf += " v";
46 }
47 if def.macros.is_some() {
48 *buf += " m";
49 }
50 if def.is_none() {
51 *buf += " _";
52 }
53
54 *buf += "\n";
55 }
56
57 for (name, child) in map.modules[module].children.iter() {
58 let path = path.to_string() + &format!("::{}", name);
59 go(buf, map, &path, *child);
60 }
61 }
62}
63
64#[test] 25#[test]
65fn crate_def_map_smoke_test() { 26fn crate_def_map_smoke_test() {
66 let map = def_map( 27 let map = def_map(