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