diff options
Diffstat (limited to 'crates/ra_hir_def/src')
-rw-r--r-- | crates/ra_hir_def/src/find_path.rs | 81 |
1 files changed, 43 insertions, 38 deletions
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index d9e67607f..ebfd6e211 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -11,6 +11,34 @@ use hir_expand::name::{known, Name}; | |||
11 | 11 | ||
12 | const MAX_PATH_LEN: usize = 15; | 12 | const MAX_PATH_LEN: usize = 15; |
13 | 13 | ||
14 | impl ModPath { | ||
15 | fn starts_with_std(&self) -> bool { | ||
16 | self.segments.first().filter(|&first_segment| first_segment == &known::std).is_some() | ||
17 | } | ||
18 | |||
19 | // When std library is present, paths starting with `std::` | ||
20 | // should be preferred over paths starting with `core::` and `alloc::` | ||
21 | fn should_start_with_std(&self) -> bool { | ||
22 | self.segments | ||
23 | .first() | ||
24 | .filter(|&first_segment| { | ||
25 | first_segment == &known::alloc || first_segment == &known::core | ||
26 | }) | ||
27 | .is_some() | ||
28 | } | ||
29 | |||
30 | fn len(&self) -> usize { | ||
31 | self.segments.len() | ||
32 | + match self.kind { | ||
33 | PathKind::Plain => 0, | ||
34 | PathKind::Super(i) => i as usize, | ||
35 | PathKind::Crate => 1, | ||
36 | PathKind::Abs => 0, | ||
37 | PathKind::DollarCrate(_) => 1, | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
14 | // FIXME: handle local items | 42 | // FIXME: handle local items |
15 | 43 | ||
16 | /// Find a path that can be used to refer to a certain item. This can depend on | 44 | /// Find a path that can be used to refer to a certain item. This can depend on |
@@ -102,7 +130,7 @@ fn find_path_inner( | |||
102 | let mut best_path = None; | 130 | let mut best_path = None; |
103 | let mut best_path_len = max_len; | 131 | let mut best_path_len = max_len; |
104 | for (module_id, name) in importable_locations { | 132 | for (module_id, name) in importable_locations { |
105 | let mut new_path = match find_path_inner( | 133 | let mut path = match find_path_inner( |
106 | db, | 134 | db, |
107 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), | 135 | ItemInNs::Types(ModuleDefId::ModuleId(module_id)), |
108 | from, | 136 | from, |
@@ -111,51 +139,28 @@ fn find_path_inner( | |||
111 | None => continue, | 139 | None => continue, |
112 | Some(path) => path, | 140 | Some(path) => path, |
113 | }; | 141 | }; |
114 | new_path.segments.push(name); | 142 | path.segments.push(name); |
115 | 143 | ||
116 | if prefer_new_path(best_path_len, best_path.as_ref(), &new_path) { | 144 | let new_path = |
117 | best_path_len = path_len(&new_path); | 145 | if let Some(best_path) = best_path { select_best_path(best_path, path) } else { path }; |
118 | best_path = Some(new_path); | 146 | best_path_len = new_path.len(); |
119 | } | 147 | best_path = Some(new_path); |
120 | } | 148 | } |
121 | best_path | 149 | best_path |
122 | } | 150 | } |
123 | 151 | ||
124 | fn prefer_new_path(old_path_len: usize, old_path: Option<&ModPath>, new_path: &ModPath) -> bool { | 152 | fn select_best_path(old_path: ModPath, new_path: ModPath) -> ModPath { |
125 | match (old_path.and_then(|mod_path| mod_path.segments.first()), new_path.segments.first()) { | 153 | if old_path.starts_with_std() && new_path.should_start_with_std() { |
126 | (Some(old_path_start), Some(new_path_start)) | 154 | old_path |
127 | if old_path_start == &known::std && use_std_instead(new_path_start) => | 155 | } else if new_path.starts_with_std() && old_path.should_start_with_std() { |
128 | { | 156 | new_path |
129 | false | 157 | } else if new_path.len() < old_path.len() { |
130 | } | 158 | new_path |
131 | (Some(old_path_start), Some(new_path_start)) | 159 | } else { |
132 | if new_path_start == &known::std && use_std_instead(old_path_start) => | 160 | old_path |
133 | { | ||
134 | true | ||
135 | } | ||
136 | (None, Some(_)) => true, | ||
137 | (Some(_), None) => false, | ||
138 | _ => path_len(new_path) < old_path_len, | ||
139 | } | 161 | } |
140 | } | 162 | } |
141 | 163 | ||
142 | // When std library is present, paths starting with `std::` | ||
143 | // should be preferred over paths starting with `core::` and `alloc::` | ||
144 | fn use_std_instead(name: &Name) -> bool { | ||
145 | name == &known::core || name == &known::alloc | ||
146 | } | ||
147 | |||
148 | fn path_len(path: &ModPath) -> usize { | ||
149 | path.segments.len() | ||
150 | + match path.kind { | ||
151 | PathKind::Plain => 0, | ||
152 | PathKind::Super(i) => i as usize, | ||
153 | PathKind::Crate => 1, | ||
154 | PathKind::Abs => 0, | ||
155 | PathKind::DollarCrate(_) => 1, | ||
156 | } | ||
157 | } | ||
158 | |||
159 | fn find_importable_locations( | 164 | fn find_importable_locations( |
160 | db: &impl DefDatabase, | 165 | db: &impl DefDatabase, |
161 | item: ItemInNs, | 166 | item: ItemInNs, |