diff options
Diffstat (limited to 'crates/ra_assists/src')
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 155 |
1 files changed, 53 insertions, 102 deletions
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 903f11e4f..c4aea2a06 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -3,8 +3,7 @@ use crate::{ | |||
3 | insert_use_statement, AssistId, | 3 | insert_use_statement, AssistId, |
4 | }; | 4 | }; |
5 | use hir::{ | 5 | use hir::{ |
6 | db::{DefDatabase, HirDatabase}, | 6 | db::HirDatabase, AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, |
7 | AsAssocItem, AssocItem, AssocItemContainer, Crate, ModPath, Module, ModuleDef, PathResolution, | ||
8 | SourceAnalyzer, Trait, Type, | 7 | SourceAnalyzer, Trait, Type, |
9 | }; | 8 | }; |
10 | use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; | 9 | use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; |
@@ -141,121 +140,73 @@ impl AutoImportAssets { | |||
141 | ImportsLocator::new(db) | 140 | ImportsLocator::new(db) |
142 | .find_imports(&self.get_search_query()) | 141 | .find_imports(&self.get_search_query()) |
143 | .into_iter() | 142 | .into_iter() |
144 | .map(|module_def| match &self.import_candidate { | 143 | .filter_map(|module_def| match &self.import_candidate { |
145 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { | 144 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { |
146 | let located_assoc_item = match module_def { | 145 | let located_assoc_item = match module_def { |
147 | ModuleDef::Function(located_function) => { | 146 | ModuleDef::Function(located_function) => located_function |
148 | Some(AssocItem::Function(located_function)) | 147 | .as_assoc_item(db) |
149 | } | 148 | .map(|assoc| assoc.container(db)) |
150 | ModuleDef::Const(located_const) => Some(AssocItem::Const(located_const)), | 149 | .and_then(Self::assoc_to_trait), |
150 | ModuleDef::Const(located_const) => located_const | ||
151 | .as_assoc_item(db) | ||
152 | .map(|assoc| assoc.container(db)) | ||
153 | .and_then(Self::assoc_to_trait), | ||
151 | _ => None, | 154 | _ => None, |
152 | }; | 155 | }?; |
153 | 156 | ||
154 | let mut applicable_traits = Vec::new(); | 157 | let mut trait_candidates = FxHashSet::default(); |
155 | if let Some(located_assoc_item) = located_assoc_item { | 158 | trait_candidates.insert(located_assoc_item.into()); |
156 | let trait_candidates: FxHashSet<_> = | 159 | |
157 | Self::get_trait_candidates(db, located_assoc_item, current_crate) | 160 | assoc_item_type |
158 | .into_iter() | 161 | .iterate_path_candidates( |
159 | .map(|trait_candidate| trait_candidate.into()) | 162 | db, |
160 | .collect(); | 163 | current_crate, |
161 | if !trait_candidates.is_empty() { | 164 | &trait_candidates, |
162 | assoc_item_type.iterate_path_candidates( | 165 | None, |
163 | db, | 166 | |_, assoc| Self::assoc_to_trait(assoc.container(db)), |
164 | current_crate, | 167 | ) |
165 | &trait_candidates, | 168 | .map(ModuleDef::from) |
166 | None, | ||
167 | |_, assoc| { | ||
168 | if let AssocItemContainer::Trait(appropriate_trait) = | ||
169 | assoc.container(db) | ||
170 | { | ||
171 | applicable_traits.push( | ||
172 | self.module_with_name_to_import | ||
173 | .find_use_path(db, appropriate_trait.into()), | ||
174 | ); | ||
175 | }; | ||
176 | None::<()> | ||
177 | }, | ||
178 | ); | ||
179 | }; | ||
180 | } | ||
181 | applicable_traits | ||
182 | } | 169 | } |
183 | ImportCandidate::TraitMethod(function_callee, _) => { | 170 | ImportCandidate::TraitMethod(function_callee, _) => { |
184 | let mut applicable_traits = Vec::new(); | 171 | let located_assoc_item = |
185 | if let ModuleDef::Function(located_function) = module_def { | 172 | if let ModuleDef::Function(located_function) = module_def { |
186 | let trait_candidates: FxHashSet<_> = Self::get_trait_candidates( | 173 | located_function |
174 | .as_assoc_item(db) | ||
175 | .map(|assoc| assoc.container(db)) | ||
176 | .and_then(Self::assoc_to_trait) | ||
177 | } else { | ||
178 | None | ||
179 | }?; | ||
180 | |||
181 | let mut trait_candidates = FxHashSet::default(); | ||
182 | trait_candidates.insert(located_assoc_item.into()); | ||
183 | |||
184 | function_callee | ||
185 | .iterate_method_candidates( | ||
187 | db, | 186 | db, |
188 | AssocItem::Function(located_function), | ||
189 | current_crate, | 187 | current_crate, |
188 | &trait_candidates, | ||
189 | None, | ||
190 | |_, function| { | ||
191 | Self::assoc_to_trait(function.as_assoc_item(db)?.container(db)) | ||
192 | }, | ||
190 | ) | 193 | ) |
191 | .into_iter() | 194 | .map(ModuleDef::from) |
192 | .map(|trait_candidate| trait_candidate.into()) | ||
193 | .collect(); | ||
194 | if !trait_candidates.is_empty() { | ||
195 | function_callee.iterate_method_candidates( | ||
196 | db, | ||
197 | current_crate, | ||
198 | &trait_candidates, | ||
199 | None, | ||
200 | |_, function| { | ||
201 | if let AssocItemContainer::Trait(appropriate_trait) = function | ||
202 | .as_assoc_item(db) | ||
203 | .expect("Function is an assoc item") | ||
204 | .container(db) | ||
205 | { | ||
206 | applicable_traits.push( | ||
207 | self.module_with_name_to_import | ||
208 | .find_use_path(db, appropriate_trait.into()), | ||
209 | ); | ||
210 | }; | ||
211 | None::<()> | ||
212 | }, | ||
213 | ); | ||
214 | } | ||
215 | } | ||
216 | applicable_traits | ||
217 | } | 195 | } |
218 | _ => vec![self.module_with_name_to_import.find_use_path(db, module_def)], | 196 | _ => Some(module_def), |
219 | }) | 197 | }) |
220 | .flatten() | 198 | .filter_map(|module_def| self.module_with_name_to_import.find_use_path(db, module_def)) |
221 | .filter_map(std::convert::identity) | ||
222 | .filter(|use_path| !use_path.segments.is_empty()) | 199 | .filter(|use_path| !use_path.segments.is_empty()) |
223 | .take(20) | 200 | .take(20) |
224 | .collect::<BTreeSet<_>>() | 201 | .collect::<BTreeSet<_>>() |
225 | } | 202 | } |
226 | 203 | ||
227 | fn get_trait_candidates( | 204 | fn assoc_to_trait(assoc: AssocItemContainer) -> Option<Trait> { |
228 | db: &RootDatabase, | 205 | if let AssocItemContainer::Trait(extracted_trait) = assoc { |
229 | called_assoc_item: AssocItem, | 206 | Some(extracted_trait) |
230 | root_crate: Crate, | 207 | } else { |
231 | ) -> FxHashSet<Trait> { | 208 | None |
232 | let _p = profile("auto_import::get_trait_candidates"); | 209 | } |
233 | root_crate | ||
234 | .dependencies(db) | ||
235 | .into_iter() | ||
236 | .map(|dependency| db.crate_def_map(dependency.krate.into())) | ||
237 | .chain(std::iter::once(db.crate_def_map(root_crate.into()))) | ||
238 | .map(|crate_def_map| { | ||
239 | crate_def_map | ||
240 | .modules | ||
241 | .iter() | ||
242 | .map(|(_, module_data)| module_data.scope.declarations()) | ||
243 | .flatten() | ||
244 | .filter_map(|module_def_id| match module_def_id.into() { | ||
245 | ModuleDef::Trait(trait_candidate) | ||
246 | if trait_candidate | ||
247 | .items(db) | ||
248 | .into_iter() | ||
249 | .any(|item| item == called_assoc_item) => | ||
250 | { | ||
251 | Some(trait_candidate) | ||
252 | } | ||
253 | _ => None, | ||
254 | }) | ||
255 | .collect::<FxHashSet<_>>() | ||
256 | }) | ||
257 | .flatten() | ||
258 | .collect() | ||
259 | } | 210 | } |
260 | } | 211 | } |
261 | 212 | ||