aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2021-02-24 23:06:31 +0000
committerKirill Bulatov <[email protected]>2021-03-08 21:59:18 +0000
commit582cee2cdf5355b681f14bbb33bd5c431c284d87 (patch)
tree47d25e9c057759b1aa334abf3f584f1d0317d941
parent309421c117fc20e58b9f30fb28a01a89f50b0086 (diff)
Return more data about located imports
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs10
-rw-r--r--crates/ide_assists/src/handlers/qualify_path.rs17
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs23
-rw-r--r--crates/ide_completion/src/item.rs28
-rw-r--r--crates/ide_completion/src/lib.rs20
-rw-r--r--crates/ide_completion/src/render.rs2
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs179
-rw-r--r--crates/ide_db/src/imports_locator.rs11
-rw-r--r--crates/rust-analyzer/src/handlers.rs7
9 files changed, 172 insertions, 125 deletions
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 5fe3f47fd..7188724be 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -92,14 +92,18 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
92 let range = ctx.sema.original_range(&syntax_under_caret).range; 92 let range = ctx.sema.original_range(&syntax_under_caret).range;
93 let group = import_group_message(import_assets.import_candidate()); 93 let group = import_group_message(import_assets.import_candidate());
94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?; 94 let scope = ImportScope::find_insert_use_container(&syntax_under_caret, &ctx.sema)?;
95 for (import, _) in proposed_imports { 95 for import in proposed_imports {
96 acc.add_group( 96 acc.add_group(
97 &group, 97 &group,
98 AssistId("auto_import", AssistKind::QuickFix), 98 AssistId("auto_import", AssistKind::QuickFix),
99 format!("Import `{}`", &import), 99 format!("Import `{}`", import.display_path()),
100 range, 100 range,
101 |builder| { 101 |builder| {
102 let rewriter = insert_use(&scope, mod_path_to_ast(&import), ctx.config.insert_use); 102 let rewriter = insert_use(
103 &scope,
104 mod_path_to_ast(import.import_path()),
105 ctx.config.insert_use,
106 );
103 builder.rewrite(rewriter); 107 builder.rewrite(rewriter);
104 }, 108 },
105 ); 109 );
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs
index c0463311e..a40cdd80e 100644
--- a/crates/ide_assists/src/handlers/qualify_path.rs
+++ b/crates/ide_assists/src/handlers/qualify_path.rs
@@ -74,17 +74,17 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
74 }; 74 };
75 75
76 let group_label = group_label(candidate); 76 let group_label = group_label(candidate);
77 for (import, item) in proposed_imports { 77 for import in proposed_imports {
78 acc.add_group( 78 acc.add_group(
79 &group_label, 79 &group_label,
80 AssistId("qualify_path", AssistKind::QuickFix), 80 AssistId("qualify_path", AssistKind::QuickFix),
81 label(candidate, &import), 81 label(candidate, import.display_path()),
82 range, 82 range,
83 |builder| { 83 |builder| {
84 qualify_candidate.qualify( 84 qualify_candidate.qualify(
85 |replace_with: String| builder.replace(range, replace_with), 85 |replace_with: String| builder.replace(range, replace_with),
86 import, 86 import.import_path(),
87 item, 87 import.item_to_import(),
88 ) 88 )
89 }, 89 },
90 ); 90 );
@@ -100,8 +100,13 @@ enum QualifyCandidate<'db> {
100} 100}
101 101
102impl QualifyCandidate<'_> { 102impl QualifyCandidate<'_> {
103 fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) { 103 fn qualify(
104 let import = mod_path_to_ast(&import); 104 &self,
105 mut replacer: impl FnMut(String),
106 import: &hir::ModPath,
107 item: hir::ItemInNs,
108 ) {
109 let import = mod_path_to_ast(import);
105 match self { 110 match self {
106 QualifyCandidate::QualifierStart(segment, generics) => { 111 QualifyCandidate::QualifierStart(segment, generics) => {
107 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string); 112 let generics = generics.as_ref().map_or_else(String::new, ToString::to_string);
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 64b60bbdd..8ff76688e 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -96,21 +96,21 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
96 let mut all_mod_paths = import_assets 96 let mut all_mod_paths = import_assets
97 .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) 97 .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
98 .into_iter() 98 .into_iter()
99 .map(|(mod_path, item_in_ns)| { 99 .map(|import| {
100 let scope_item = match item_in_ns { 100 let proposed_def = match import.item_to_import() {
101 hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()), 101 hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()),
102 hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()), 102 hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()),
103 hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()), 103 hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()),
104 }; 104 };
105 (mod_path, scope_item) 105 (import, proposed_def)
106 }) 106 })
107 .filter(|(_, proposed_def)| !scope_definitions.contains(proposed_def)) 107 .filter(|(_, proposed_def)| !scope_definitions.contains(proposed_def))
108 .collect::<Vec<_>>(); 108 .collect::<Vec<_>>();
109 all_mod_paths.sort_by_cached_key(|(mod_path, _)| { 109 all_mod_paths.sort_by_cached_key(|(import, _)| {
110 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) 110 compute_fuzzy_completion_order_key(import.display_path(), &user_input_lowercased)
111 }); 111 });
112 112
113 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { 113 acc.add_all(all_mod_paths.into_iter().filter_map(|(import, definition)| {
114 let import_for_trait_assoc_item = match definition { 114 let import_for_trait_assoc_item = match definition {
115 ScopeDef::ModuleDef(module_def) => module_def 115 ScopeDef::ModuleDef(module_def) => module_def
116 .as_assoc_item(ctx.db) 116 .as_assoc_item(ctx.db)
@@ -118,11 +118,8 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
118 .is_some(), 118 .is_some(),
119 _ => false, 119 _ => false,
120 }; 120 };
121 let import_edit = ImportEdit { 121 let import_edit =
122 import_path, 122 ImportEdit { import, import_scope: import_scope.clone(), import_for_trait_assoc_item };
123 import_scope: import_scope.clone(),
124 import_for_trait_assoc_item,
125 };
126 render_resolution_with_import(RenderContext::new(ctx), import_edit, &definition) 123 render_resolution_with_import(RenderContext::new(ctx), import_edit, &definition)
127 })); 124 }));
128 Some(()) 125 Some(())
@@ -186,11 +183,11 @@ fn compute_fuzzy_completion_order_key(
186 user_input_lowercased: &str, 183 user_input_lowercased: &str,
187) -> usize { 184) -> usize {
188 cov_mark::hit!(certain_fuzzy_order_test); 185 cov_mark::hit!(certain_fuzzy_order_test);
189 let proposed_import_name = match proposed_mod_path.segments().last() { 186 let import_name = match proposed_mod_path.segments().last() {
190 Some(name) => name.to_string().to_lowercase(), 187 Some(name) => name.to_string().to_lowercase(),
191 None => return usize::MAX, 188 None => return usize::MAX,
192 }; 189 };
193 match proposed_import_name.match_indices(user_input_lowercased).next() { 190 match import_name.match_indices(user_input_lowercased).next() {
194 Some((first_matching_index, _)) => first_matching_index, 191 Some((first_matching_index, _)) => first_matching_index,
195 None => usize::MAX, 192 None => usize::MAX,
196 } 193 }
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 9b2435c4b..0390fe226 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -2,9 +2,10 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5use hir::{Documentation, ModPath, Mutability}; 5use hir::{Documentation, Mutability};
6use ide_db::{ 6use ide_db::{
7 helpers::{ 7 helpers::{
8 import_assets::LocatedImport,
8 insert_use::{self, ImportScope, InsertUseConfig}, 9 insert_use::{self, ImportScope, InsertUseConfig},
9 mod_path_to_ast, SnippetCap, 10 mod_path_to_ast, SnippetCap,
10 }, 11 },
@@ -272,7 +273,7 @@ impl CompletionItem {
272/// An extra import to add after the completion is applied. 273/// An extra import to add after the completion is applied.
273#[derive(Debug, Clone)] 274#[derive(Debug, Clone)]
274pub struct ImportEdit { 275pub struct ImportEdit {
275 pub import_path: ModPath, 276 pub import: LocatedImport,
276 pub import_scope: ImportScope, 277 pub import_scope: ImportScope,
277 pub import_for_trait_assoc_item: bool, 278 pub import_for_trait_assoc_item: bool,
278} 279}
@@ -283,8 +284,11 @@ impl ImportEdit {
283 pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> { 284 pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> {
284 let _p = profile::span("ImportEdit::to_text_edit"); 285 let _p = profile::span("ImportEdit::to_text_edit");
285 286
286 let rewriter = 287 let rewriter = insert_use::insert_use(
287 insert_use::insert_use(&self.import_scope, mod_path_to_ast(&self.import_path), cfg); 288 &self.import_scope,
289 mod_path_to_ast(self.import.import_path()),
290 cfg,
291 );
288 let old_ast = rewriter.rewrite_root()?; 292 let old_ast = rewriter.rewrite_root()?;
289 let mut import_insert = TextEdit::builder(); 293 let mut import_insert = TextEdit::builder();
290 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert); 294 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut import_insert);
@@ -323,19 +327,13 @@ impl Builder {
323 let mut insert_text = self.insert_text; 327 let mut insert_text = self.insert_text;
324 328
325 if let Some(import_to_add) = self.import_to_add.as_ref() { 329 if let Some(import_to_add) = self.import_to_add.as_ref() {
330 lookup = lookup.or_else(|| Some(label.clone()));
331 insert_text = insert_text.or_else(|| Some(label.clone()));
332 let display_path = import_to_add.import.display_path();
326 if import_to_add.import_for_trait_assoc_item { 333 if import_to_add.import_for_trait_assoc_item {
327 lookup = lookup.or_else(|| Some(label.clone())); 334 label = format!("{} ({})", label, display_path);
328 insert_text = insert_text.or_else(|| Some(label.clone()));
329 label = format!("{} ({})", label, import_to_add.import_path);
330 } else { 335 } else {
331 let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); 336 label = display_path.to_string();
332 let _ = import_path_without_last_segment.pop_segment();
333
334 if !import_path_without_last_segment.segments().is_empty() {
335 lookup = lookup.or_else(|| Some(label.clone()));
336 insert_text = insert_text.or_else(|| Some(label.clone()));
337 label = format!("{}::{}", import_path_without_last_segment, label);
338 }
339 } 337 }
340 } 338 }
341 339
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index b0b809791..ca2e5e706 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -13,7 +13,9 @@ mod completions;
13 13
14use completions::flyimport::position_for_import; 14use completions::flyimport::position_for_import;
15use ide_db::{ 15use ide_db::{
16 base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase, 16 base_db::FilePosition,
17 helpers::{import_assets::LocatedImport, insert_use::ImportScope},
18 imports_locator, RootDatabase,
17}; 19};
18use text_edit::TextEdit; 20use text_edit::TextEdit;
19 21
@@ -148,12 +150,16 @@ pub fn resolve_completion_edits(
148 let current_module = ctx.sema.scope(position_for_import).module()?; 150 let current_module = ctx.sema.scope(position_for_import).module()?;
149 let current_crate = current_module.krate(); 151 let current_crate = current_module.krate();
150 152
151 let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) 153 let (import_path, item_to_import) =
152 .filter_map(|candidate| { 154 imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name)
153 let item: hir::ItemInNs = candidate.either(Into::into, Into::into); 155 .filter_map(|candidate| {
154 current_module.find_use_path_prefixed(db, item, config.insert_use.prefix_kind) 156 let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
155 }) 157 current_module
156 .find(|mod_path| mod_path.to_string() == full_import_path)?; 158 .find_use_path_prefixed(db, item, config.insert_use.prefix_kind)
159 .zip(Some(item))
160 })
161 .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
162 let import = LocatedImport::new(import_path, item_to_import, None);
157 163
158 ImportEdit { import_path, import_scope, import_for_trait_assoc_item } 164 ImportEdit { import_path, import_scope, import_for_trait_assoc_item }
159 .to_text_edit(config.insert_use) 165 .to_text_edit(config.insert_use)
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index dcfac23c5..df26e7642 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -56,7 +56,7 @@ pub(crate) fn render_resolution_with_import<'a>(
56 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), 56 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(),
57 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), 57 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(),
58 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), 58 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(),
59 _ => import_edit.import_path.segments().last()?.to_string(), 59 _ => import_edit.import.display_path().segments().last()?.to_string(),
60 }; 60 };
61 Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| { 61 Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| {
62 item.completion_kind = CompletionKind::Magic; 62 item.completion_kind = CompletionKind::Magic;
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index dc3b92a64..d8bf61aaa 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -117,6 +117,42 @@ impl ImportAssets {
117 } 117 }
118} 118}
119 119
120#[derive(Debug, Clone, PartialEq, Eq, Hash)]
121pub struct LocatedImport {
122 import_path: ModPath,
123 item_to_import: ItemInNs,
124 import_display_override: Option<(ModPath, ItemInNs)>,
125}
126
127impl LocatedImport {
128 pub fn new(
129 import_path: ModPath,
130 item_to_import: ItemInNs,
131 import_display_override: Option<(ModPath, ItemInNs)>,
132 ) -> Self {
133 Self { import_path, item_to_import, import_display_override }
134 }
135
136 pub fn display_path(&self) -> &ModPath {
137 self.import_display_override
138 .as_ref()
139 .map(|(mod_path, _)| mod_path)
140 .unwrap_or(&self.import_path)
141 }
142
143 pub fn import_path(&self) -> &ModPath {
144 &self.import_path
145 }
146
147 pub fn item_to_display(&self) -> ItemInNs {
148 self.import_display_override.as_ref().map(|&(_, item)| item).unwrap_or(self.item_to_import)
149 }
150
151 pub fn item_to_import(&self) -> ItemInNs {
152 self.item_to_import
153 }
154}
155
120impl ImportAssets { 156impl ImportAssets {
121 pub fn import_candidate(&self) -> &ImportCandidate { 157 pub fn import_candidate(&self) -> &ImportCandidate {
122 &self.import_candidate 158 &self.import_candidate
@@ -134,16 +170,13 @@ impl ImportAssets {
134 &self, 170 &self,
135 sema: &Semantics<RootDatabase>, 171 sema: &Semantics<RootDatabase>,
136 prefix_kind: PrefixKind, 172 prefix_kind: PrefixKind,
137 ) -> Vec<(hir::ModPath, hir::ItemInNs)> { 173 ) -> Vec<LocatedImport> {
138 let _p = profile::span("import_assets::search_for_imports"); 174 let _p = profile::span("import_assets::search_for_imports");
139 self.search_for(sema, Some(prefix_kind)) 175 self.search_for(sema, Some(prefix_kind))
140 } 176 }
141 177
142 /// This may return non-absolute paths if a part of the returned path is already imported into scope. 178 /// This may return non-absolute paths if a part of the returned path is already imported into scope.
143 pub fn search_for_relative_paths( 179 pub fn search_for_relative_paths(&self, sema: &Semantics<RootDatabase>) -> Vec<LocatedImport> {
144 &self,
145 sema: &Semantics<RootDatabase>,
146 ) -> Vec<(hir::ModPath, hir::ItemInNs)> {
147 let _p = profile::span("import_assets::search_for_relative_paths"); 180 let _p = profile::span("import_assets::search_for_relative_paths");
148 self.search_for(sema, None) 181 self.search_for(sema, None)
149 } 182 }
@@ -152,7 +185,7 @@ impl ImportAssets {
152 &self, 185 &self,
153 sema: &Semantics<RootDatabase>, 186 sema: &Semantics<RootDatabase>,
154 prefixed: Option<hir::PrefixKind>, 187 prefixed: Option<hir::PrefixKind>,
155 ) -> Vec<(hir::ModPath, hir::ItemInNs)> { 188 ) -> Vec<LocatedImport> {
156 let current_crate = self.module_with_candidate.krate(); 189 let current_crate = self.module_with_candidate.krate();
157 190
158 let imports_for_candidate_name = match self.name_to_import() { 191 let imports_for_candidate_name = match self.name_to_import() {
@@ -181,61 +214,53 @@ impl ImportAssets {
181 } 214 }
182 }; 215 };
183 216
184 let mut res = self 217 self.applicable_defs(sema.db, prefixed, imports_for_candidate_name)
185 .applicable_defs(sema, prefixed, imports_for_candidate_name) 218 .into_iter()
186 .filter(|(use_path, _)| use_path.len() > 1) 219 .filter(|import| import.import_path().len() > 1)
187 .collect::<Vec<_>>(); 220 .collect()
188 res.sort_by_cached_key(|(path, _)| path.clone());
189 res
190 } 221 }
191 222
192 fn applicable_defs<'a>( 223 fn applicable_defs(
193 &'a self, 224 &self,
194 sema: &'a Semantics<RootDatabase>, 225 db: &RootDatabase,
195 prefixed: Option<hir::PrefixKind>, 226 prefixed: Option<hir::PrefixKind>,
196 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, 227 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
197 ) -> Box<dyn Iterator<Item = (ModPath, ItemInNs)> + 'a> { 228 ) -> FxHashSet<LocatedImport> {
198 let current_crate = self.module_with_candidate.krate(); 229 let current_crate = self.module_with_candidate.krate();
199 let db = sema.db; 230
231 let import_path_locator =
232 |item| get_mod_path(db, item, &self.module_with_candidate, prefixed);
200 233
201 match &self.import_candidate { 234 match &self.import_candidate {
202 ImportCandidate::Path(path_candidate) => Box::new( 235 ImportCandidate::Path(path_candidate) => {
203 path_applicable_items( 236 path_applicable_imports(db, path_candidate, import_path_locator, unfiltered_defs)
204 db, 237 }
205 path_candidate, 238 ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items(
206 &self.module_with_candidate, 239 db,
207 prefixed, 240 current_crate,
208 unfiltered_defs, 241 trait_candidate,
209 ) 242 true,
210 .into_iter(), 243 import_path_locator,
211 ), 244 unfiltered_defs,
212 ImportCandidate::TraitAssocItem(trait_candidate) => Box::new(
213 trait_applicable_defs(db, current_crate, trait_candidate, true, unfiltered_defs)
214 .into_iter()
215 .filter_map(move |item_to_search| {
216 get_mod_path(db, item_to_search, &self.module_with_candidate, prefixed)
217 .zip(Some(item_to_search))
218 }),
219 ), 245 ),
220 ImportCandidate::TraitMethod(trait_candidate) => Box::new( 246 ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items(
221 trait_applicable_defs(db, current_crate, trait_candidate, false, unfiltered_defs) 247 db,
222 .into_iter() 248 current_crate,
223 .filter_map(move |item_to_search| { 249 trait_candidate,
224 get_mod_path(db, item_to_search, &self.module_with_candidate, prefixed) 250 false,
225 .zip(Some(item_to_search)) 251 import_path_locator,
226 }), 252 unfiltered_defs,
227 ), 253 ),
228 } 254 }
229 } 255 }
230} 256}
231 257
232fn path_applicable_items<'a>( 258fn path_applicable_imports(
233 db: &'a RootDatabase, 259 db: &RootDatabase,
234 path_candidate: &'a PathImportCandidate, 260 path_candidate: &PathImportCandidate,
235 module_with_candidate: &hir::Module, 261 import_path_locator: impl Fn(ItemInNs) -> Option<ModPath>,
236 prefixed: Option<hir::PrefixKind>, 262 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
237 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, 263) -> FxHashSet<LocatedImport> {
238) -> FxHashSet<(ModPath, ItemInNs)> {
239 let applicable_items = unfiltered_defs 264 let applicable_items = unfiltered_defs
240 .filter_map(|def| { 265 .filter_map(|def| {
241 let (assoc_original, candidate) = match def { 266 let (assoc_original, candidate) = match def {
@@ -256,14 +281,15 @@ fn path_applicable_items<'a>(
256 Some((assoc_original, candidate)) 281 Some((assoc_original, candidate))
257 }) 282 })
258 .filter_map(|(assoc_original, candidate)| { 283 .filter_map(|(assoc_original, candidate)| {
259 get_mod_path(db, candidate, module_with_candidate, prefixed) 284 import_path_locator(candidate).zip(Some((assoc_original, candidate)))
260 .zip(Some((assoc_original, candidate)))
261 }); 285 });
262 286
263 let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { 287 let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier {
264 Qualifier::Absent => { 288 Qualifier::Absent => {
265 return applicable_items 289 return applicable_items
266 .map(|(candidate_path, (_, candidate))| (candidate_path, candidate)) 290 .map(|(candidate_path, (_, candidate))| {
291 LocatedImport::new(candidate_path, candidate, None)
292 })
267 .collect(); 293 .collect();
268 } 294 }
269 Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => (first_segment, qualifier), 295 Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => (first_segment, qualifier),
@@ -283,19 +309,22 @@ fn path_applicable_items<'a>(
283 .filter_map(|(candidate_path, (assoc_original, candidate))| { 309 .filter_map(|(candidate_path, (assoc_original, candidate))| {
284 if let Some(assoc_original) = assoc_original { 310 if let Some(assoc_original) = assoc_original {
285 if item_name(db, candidate)?.to_string() == unresolved_first_segment_string { 311 if item_name(db, candidate)?.to_string() == unresolved_first_segment_string {
286 return Some((candidate_path, ItemInNs::from(assoc_original))); 312 return Some(LocatedImport::new(
313 candidate_path.clone(),
314 ItemInNs::from(assoc_original),
315 Some((candidate_path, candidate)),
316 ));
287 } 317 }
288 } 318 }
289 319
290 let matching_module = 320 let matching_module =
291 module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; 321 module_with_matching_name(db, &unresolved_first_segment_string, candidate)?;
292 let path = get_mod_path( 322 let item = ItemInNs::from(ModuleDef::from(matching_module));
293 db, 323 Some(LocatedImport::new(
294 ItemInNs::from(ModuleDef::from(matching_module)), 324 import_path_locator(item)?,
295 module_with_candidate, 325 item,
296 prefixed, 326 Some((candidate_path, candidate)),
297 )?; 327 ))
298 Some((path, candidate))
299 }) 328 })
300 .collect() 329 .collect()
301} 330}
@@ -336,13 +365,14 @@ fn module_with_matching_name(
336 None 365 None
337} 366}
338 367
339fn trait_applicable_defs<'a>( 368fn trait_applicable_items(
340 db: &'a RootDatabase, 369 db: &RootDatabase,
341 current_crate: Crate, 370 current_crate: Crate,
342 trait_candidate: &TraitImportCandidate, 371 trait_candidate: &TraitImportCandidate,
343 trait_assoc_item: bool, 372 trait_assoc_item: bool,
344 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a, 373 import_path_locator: impl Fn(ItemInNs) -> Option<ModPath>,
345) -> FxHashSet<ItemInNs> { 374 unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>,
375) -> FxHashSet<LocatedImport> {
346 let mut required_assoc_items = FxHashSet::default(); 376 let mut required_assoc_items = FxHashSet::default();
347 377
348 let trait_candidates = unfiltered_defs 378 let trait_candidates = unfiltered_defs
@@ -357,7 +387,7 @@ fn trait_applicable_defs<'a>(
357 }) 387 })
358 .collect(); 388 .collect();
359 389
360 let mut applicable_traits = FxHashSet::default(); 390 let mut located_imports = FxHashSet::default();
361 391
362 if trait_assoc_item { 392 if trait_assoc_item {
363 trait_candidate.receiver_ty.iterate_path_candidates( 393 trait_candidate.receiver_ty.iterate_path_candidates(
@@ -372,8 +402,13 @@ fn trait_applicable_defs<'a>(
372 return None; 402 return None;
373 } 403 }
374 } 404 }
375 applicable_traits 405
376 .insert(ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?))); 406 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
407 located_imports.insert(LocatedImport::new(
408 import_path_locator(item)?,
409 item,
410 None,
411 ));
377 } 412 }
378 None::<()> 413 None::<()>
379 }, 414 },
@@ -387,15 +422,19 @@ fn trait_applicable_defs<'a>(
387 |_, function| { 422 |_, function| {
388 let assoc = function.as_assoc_item(db)?; 423 let assoc = function.as_assoc_item(db)?;
389 if required_assoc_items.contains(&assoc) { 424 if required_assoc_items.contains(&assoc) {
390 applicable_traits 425 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
391 .insert(ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?))); 426 located_imports.insert(LocatedImport::new(
427 import_path_locator(item)?,
428 item,
429 None,
430 ));
392 } 431 }
393 None::<()> 432 None::<()>
394 }, 433 },
395 ) 434 )
396 }; 435 };
397 436
398 applicable_traits 437 located_imports
399} 438}
400 439
401fn get_mod_path( 440fn get_mod_path(
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs
index 480cbf1ea..fd700e04f 100644
--- a/crates/ide_db/src/imports_locator.rs
+++ b/crates/ide_db/src/imports_locator.rs
@@ -17,8 +17,8 @@ use rustc_hash::FxHashSet;
17 17
18pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; 18pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40;
19 19
20pub fn find_exact_imports<'a>( 20pub fn find_exact_imports(
21 sema: &Semantics<'a, RootDatabase>, 21 sema: &Semantics<'_, RootDatabase>,
22 krate: Crate, 22 krate: Crate,
23 name_to_import: String, 23 name_to_import: String,
24) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>>> { 24) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>>> {
@@ -48,7 +48,7 @@ pub enum AssocItemSearch {
48} 48}
49 49
50pub fn find_similar_imports<'a>( 50pub fn find_similar_imports<'a>(
51 sema: &Semantics<'a, RootDatabase>, 51 sema: &'a Semantics<'a, RootDatabase>,
52 krate: Crate, 52 krate: Crate,
53 fuzzy_search_string: String, 53 fuzzy_search_string: String,
54 assoc_item_search: AssocItemSearch, 54 assoc_item_search: AssocItemSearch,
@@ -77,12 +77,11 @@ pub fn find_similar_imports<'a>(
77 local_query.limit(limit); 77 local_query.limit(limit);
78 } 78 }
79 79
80 let db = sema.db;
81 Box::new(find_imports(sema, krate, local_query, external_query).filter( 80 Box::new(find_imports(sema, krate, local_query, external_query).filter(
82 move |import_candidate| match assoc_item_search { 81 move |import_candidate| match assoc_item_search {
83 AssocItemSearch::Include => true, 82 AssocItemSearch::Include => true,
84 AssocItemSearch::Exclude => !is_assoc_item(import_candidate, db), 83 AssocItemSearch::Exclude => !is_assoc_item(import_candidate, sema.db),
85 AssocItemSearch::AssocItemsOnly => is_assoc_item(import_candidate, db), 84 AssocItemSearch::AssocItemsOnly => is_assoc_item(import_candidate, sema.db),
86 }, 85 },
87 )) 86 ))
88} 87}
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 4f6f250d6..d479d826f 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1534,14 +1534,13 @@ fn fill_resolve_data(
1534 position: &TextDocumentPositionParams, 1534 position: &TextDocumentPositionParams,
1535) -> Option<()> { 1535) -> Option<()> {
1536 let import_edit = item.import_to_add()?; 1536 let import_edit = item.import_to_add()?;
1537 let full_import_path = import_edit.import_path.to_string(); 1537 let import_path = import_edit.import.import_path();
1538 let imported_name = import_edit.import_path.segments().last()?.to_string();
1539 1538
1540 *resolve_data = Some( 1539 *resolve_data = Some(
1541 to_value(CompletionResolveData { 1540 to_value(CompletionResolveData {
1542 position: position.to_owned(), 1541 position: position.to_owned(),
1543 full_import_path, 1542 full_import_path: import_path.to_string(),
1544 imported_name, 1543 imported_name: import_path.segments().last()?.to_string(),
1545 import_for_trait_assoc_item: import_edit.import_for_trait_assoc_item, 1544 import_for_trait_assoc_item: import_edit.import_for_trait_assoc_item,
1546 }) 1545 })
1547 .unwrap(), 1546 .unwrap(),