aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs155
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};
5use hir::{ 5use 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};
10use ra_ide_db::{imports_locator::ImportsLocator, RootDatabase}; 9use 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