diff options
Diffstat (limited to 'crates/ra_hir_def/src/find_path.rs')
-rw-r--r-- | crates/ra_hir_def/src/find_path.rs | 105 |
1 files changed, 55 insertions, 50 deletions
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index 70dcb03e6..4db798473 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -1,5 +1,11 @@ | |||
1 | //! An algorithm to find a path to refer to a certain item. | 1 | //! An algorithm to find a path to refer to a certain item. |
2 | 2 | ||
3 | use std::sync::Arc; | ||
4 | |||
5 | use hir_expand::name::{known, AsName, Name}; | ||
6 | use ra_prof::profile; | ||
7 | use test_utils::mark; | ||
8 | |||
3 | use crate::{ | 9 | use crate::{ |
4 | db::DefDatabase, | 10 | db::DefDatabase, |
5 | item_scope::ItemInNs, | 11 | item_scope::ItemInNs, |
@@ -7,25 +13,28 @@ use crate::{ | |||
7 | visibility::Visibility, | 13 | visibility::Visibility, |
8 | CrateId, ModuleDefId, ModuleId, | 14 | CrateId, ModuleDefId, ModuleId, |
9 | }; | 15 | }; |
10 | use hir_expand::name::{known, AsName, Name}; | 16 | |
11 | use test_utils::tested_by; | 17 | // FIXME: handle local items |
18 | |||
19 | /// Find a path that can be used to refer to a certain item. This can depend on | ||
20 | /// *from where* you're referring to the item, hence the `from` parameter. | ||
21 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | ||
22 | let _p = profile("find_path"); | ||
23 | db.find_path_inner(item, from, MAX_PATH_LEN) | ||
24 | } | ||
12 | 25 | ||
13 | const MAX_PATH_LEN: usize = 15; | 26 | const MAX_PATH_LEN: usize = 15; |
14 | 27 | ||
15 | impl ModPath { | 28 | impl ModPath { |
16 | fn starts_with_std(&self) -> bool { | 29 | fn starts_with_std(&self) -> bool { |
17 | self.segments.first().filter(|&first_segment| first_segment == &known::std).is_some() | 30 | self.segments.first() == Some(&known::std) |
18 | } | 31 | } |
19 | 32 | ||
20 | // When std library is present, paths starting with `std::` | 33 | // When std library is present, paths starting with `std::` |
21 | // should be preferred over paths starting with `core::` and `alloc::` | 34 | // should be preferred over paths starting with `core::` and `alloc::` |
22 | fn can_start_with_std(&self) -> bool { | 35 | fn can_start_with_std(&self) -> bool { |
23 | self.segments | 36 | let first_segment = self.segments.first(); |
24 | .first() | 37 | first_segment == Some(&known::alloc) || first_segment == Some(&known::core) |
25 | .filter(|&first_segment| { | ||
26 | first_segment == &known::alloc || first_segment == &known::core | ||
27 | }) | ||
28 | .is_some() | ||
29 | } | 38 | } |
30 | 39 | ||
31 | fn len(&self) -> usize { | 40 | fn len(&self) -> usize { |
@@ -40,15 +49,7 @@ impl ModPath { | |||
40 | } | 49 | } |
41 | } | 50 | } |
42 | 51 | ||
43 | // FIXME: handle local items | 52 | pub(crate) fn find_path_inner_query( |
44 | |||
45 | /// Find a path that can be used to refer to a certain item. This can depend on | ||
46 | /// *from where* you're referring to the item, hence the `from` parameter. | ||
47 | pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> { | ||
48 | find_path_inner(db, item, from, MAX_PATH_LEN) | ||
49 | } | ||
50 | |||
51 | fn find_path_inner( | ||
52 | db: &dyn DefDatabase, | 53 | db: &dyn DefDatabase, |
53 | item: ItemInNs, | 54 | item: ItemInNs, |
54 | from: ModuleId, | 55 | from: ModuleId, |
@@ -139,8 +140,7 @@ fn find_path_inner( | |||
139 | let mut best_path = None; | 140 | let mut best_path = None; |
140 | let mut best_path_len = max_len; | 141 | let mut best_path_len = max_len; |
141 | for (module_id, name) in importable_locations { | 142 | for (module_id, name) in importable_locations { |
142 | let mut path = match find_path_inner( | 143 | let mut path = match db.find_path_inner( |
143 | db, | ||
144 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | 144 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), |
145 | from, | 145 | from, |
146 | best_path_len - 1, | 146 | best_path_len - 1, |
@@ -163,17 +163,19 @@ fn find_path_inner( | |||
163 | 163 | ||
164 | fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { | 164 | fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { |
165 | if old_path.starts_with_std() && new_path.can_start_with_std() { | 165 | if old_path.starts_with_std() && new_path.can_start_with_std() { |
166 | tested_by!(prefer_std_paths); | ||
167 | if prefer_no_std { | 166 | if prefer_no_std { |
167 | mark::hit!(prefer_no_std_paths); | ||
168 | new_path | 168 | new_path |
169 | } else { | 169 | } else { |
170 | mark::hit!(prefer_std_paths); | ||
170 | old_path | 171 | old_path |
171 | } | 172 | } |
172 | } else if new_path.starts_with_std() && old_path.can_start_with_std() { | 173 | } else if new_path.starts_with_std() && old_path.can_start_with_std() { |
173 | tested_by!(prefer_std_paths); | ||
174 | if prefer_no_std { | 174 | if prefer_no_std { |
175 | mark::hit!(prefer_no_std_paths); | ||
175 | old_path | 176 | old_path |
176 | } else { | 177 | } else { |
178 | mark::hit!(prefer_std_paths); | ||
177 | new_path | 179 | new_path |
178 | } | 180 | } |
179 | } else if new_path.len() < old_path.len() { | 181 | } else if new_path.len() < old_path.len() { |
@@ -198,7 +200,7 @@ fn find_importable_locations( | |||
198 | .chain(crate_graph[from.krate].dependencies.iter().map(|dep| dep.crate_id)) | 200 | .chain(crate_graph[from.krate].dependencies.iter().map(|dep| dep.crate_id)) |
199 | { | 201 | { |
200 | result.extend( | 202 | result.extend( |
201 | importable_locations_in_crate(db, item, krate) | 203 | db.importable_locations_of(item, krate) |
202 | .iter() | 204 | .iter() |
203 | .filter(|(_, _, vis)| vis.is_visible_from(db, from)) | 205 | .filter(|(_, _, vis)| vis.is_visible_from(db, from)) |
204 | .map(|(m, n, _)| (*m, n.clone())), | 206 | .map(|(m, n, _)| (*m, n.clone())), |
@@ -213,11 +215,12 @@ fn find_importable_locations( | |||
213 | /// | 215 | /// |
214 | /// Note that the crate doesn't need to be the one in which the item is defined; | 216 | /// Note that the crate doesn't need to be the one in which the item is defined; |
215 | /// it might be re-exported in other crates. | 217 | /// it might be re-exported in other crates. |
216 | fn importable_locations_in_crate( | 218 | pub(crate) fn importable_locations_of_query( |
217 | db: &dyn DefDatabase, | 219 | db: &dyn DefDatabase, |
218 | item: ItemInNs, | 220 | item: ItemInNs, |
219 | krate: CrateId, | 221 | krate: CrateId, |
220 | ) -> Vec<(ModuleId, Name, Visibility)> { | 222 | ) -> Arc<[(ModuleId, Name, Visibility)]> { |
223 | let _p = profile("importable_locations_of_query"); | ||
221 | let def_map = db.crate_def_map(krate); | 224 | let def_map = db.crate_def_map(krate); |
222 | let mut result = Vec::new(); | 225 | let mut result = Vec::new(); |
223 | for (local_id, data) in def_map.modules.iter() { | 226 | for (local_id, data) in def_map.modules.iter() { |
@@ -243,17 +246,20 @@ fn importable_locations_in_crate( | |||
243 | result.push((ModuleId { krate, local_id }, name.clone(), vis)); | 246 | result.push((ModuleId { krate, local_id }, name.clone(), vis)); |
244 | } | 247 | } |
245 | } | 248 | } |
246 | result | 249 | |
250 | Arc::from(result) | ||
247 | } | 251 | } |
248 | 252 | ||
249 | #[cfg(test)] | 253 | #[cfg(test)] |
250 | mod tests { | 254 | mod tests { |
251 | use super::*; | ||
252 | use crate::test_db::TestDB; | ||
253 | use hir_expand::hygiene::Hygiene; | 255 | use hir_expand::hygiene::Hygiene; |
254 | use ra_db::fixture::WithFixture; | 256 | use ra_db::fixture::WithFixture; |
255 | use ra_syntax::ast::AstNode; | 257 | use ra_syntax::ast::AstNode; |
256 | use test_utils::covers; | 258 | use test_utils::mark; |
259 | |||
260 | use crate::test_db::TestDB; | ||
261 | |||
262 | use super::*; | ||
257 | 263 | ||
258 | /// `code` needs to contain a cursor marker; checks that `find_path` for the | 264 | /// `code` needs to contain a cursor marker; checks that `find_path` for the |
259 | /// item the `path` refers to returns that same path when called from the | 265 | /// item the `path` refers to returns that same path when called from the |
@@ -508,7 +514,7 @@ mod tests { | |||
508 | 514 | ||
509 | #[test] | 515 | #[test] |
510 | fn prefer_std_paths_over_alloc() { | 516 | fn prefer_std_paths_over_alloc() { |
511 | covers!(prefer_std_paths); | 517 | mark::check!(prefer_std_paths); |
512 | let code = r#" | 518 | let code = r#" |
513 | //- /main.rs crate:main deps:alloc,std | 519 | //- /main.rs crate:main deps:alloc,std |
514 | <|> | 520 | <|> |
@@ -527,51 +533,50 @@ mod tests { | |||
527 | } | 533 | } |
528 | 534 | ||
529 | #[test] | 535 | #[test] |
530 | fn prefer_alloc_paths_over_std() { | 536 | fn prefer_core_paths_over_std() { |
531 | covers!(prefer_std_paths); | 537 | mark::check!(prefer_no_std_paths); |
532 | let code = r#" | 538 | let code = r#" |
533 | //- /main.rs crate:main deps:alloc,std | 539 | //- /main.rs crate:main deps:core,std |
534 | #![no_std] | 540 | #![no_std] |
535 | 541 | ||
536 | <|> | 542 | <|> |
537 | 543 | ||
538 | //- /std.rs crate:std deps:alloc | 544 | //- /std.rs crate:std deps:core |
539 | 545 | ||
540 | pub mod sync { | 546 | pub mod fmt { |
541 | pub use alloc::sync::Arc; | 547 | pub use core::fmt::Error; |
542 | } | 548 | } |
543 | 549 | ||
544 | //- /zzz.rs crate:alloc | 550 | //- /zzz.rs crate:core |
545 | 551 | ||
546 | pub mod sync { | 552 | pub mod fmt { |
547 | pub struct Arc; | 553 | pub struct Error; |
548 | } | 554 | } |
549 | "#; | 555 | "#; |
550 | check_found_path(code, "alloc::sync::Arc"); | 556 | check_found_path(code, "core::fmt::Error"); |
551 | } | 557 | } |
552 | 558 | ||
553 | #[test] | 559 | #[test] |
554 | fn prefer_core_paths_over_std() { | 560 | fn prefer_alloc_paths_over_std() { |
555 | covers!(prefer_std_paths); | ||
556 | let code = r#" | 561 | let code = r#" |
557 | //- /main.rs crate:main deps:core,std | 562 | //- /main.rs crate:main deps:alloc,std |
558 | #![no_std] | 563 | #![no_std] |
559 | 564 | ||
560 | <|> | 565 | <|> |
561 | 566 | ||
562 | //- /std.rs crate:std deps:core | 567 | //- /std.rs crate:std deps:alloc |
563 | 568 | ||
564 | pub mod fmt { | 569 | pub mod sync { |
565 | pub use core::fmt::Error; | 570 | pub use alloc::sync::Arc; |
566 | } | 571 | } |
567 | 572 | ||
568 | //- /zzz.rs crate:core | 573 | //- /zzz.rs crate:alloc |
569 | 574 | ||
570 | pub mod fmt { | 575 | pub mod sync { |
571 | pub struct Error; | 576 | pub struct Arc; |
572 | } | 577 | } |
573 | "#; | 578 | "#; |
574 | check_found_path(code, "core::fmt::Error"); | 579 | check_found_path(code, "alloc::sync::Arc"); |
575 | } | 580 | } |
576 | 581 | ||
577 | #[test] | 582 | #[test] |