diff options
author | Kirill Bulatov <[email protected]> | 2021-02-24 23:06:31 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2021-03-08 21:59:18 +0000 |
commit | 582cee2cdf5355b681f14bbb33bd5c431c284d87 (patch) | |
tree | 47d25e9c057759b1aa334abf3f584f1d0317d941 /crates | |
parent | 309421c117fc20e58b9f30fb28a01a89f50b0086 (diff) |
Return more data about located imports
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide_assists/src/handlers/auto_import.rs | 10 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/qualify_path.rs | 17 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 23 | ||||
-rw-r--r-- | crates/ide_completion/src/item.rs | 28 | ||||
-rw-r--r-- | crates/ide_completion/src/lib.rs | 20 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 2 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 179 | ||||
-rw-r--r-- | crates/ide_db/src/imports_locator.rs | 11 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 7 |
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 | ||
102 | impl QualifyCandidate<'_> { | 102 | impl 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 | ||
3 | use std::fmt; | 3 | use std::fmt; |
4 | 4 | ||
5 | use hir::{Documentation, ModPath, Mutability}; | 5 | use hir::{Documentation, Mutability}; |
6 | use ide_db::{ | 6 | use 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)] |
274 | pub struct ImportEdit { | 275 | pub 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 | ||
14 | use completions::flyimport::position_for_import; | 14 | use completions::flyimport::position_for_import; |
15 | use ide_db::{ | 15 | use 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 | }; |
18 | use text_edit::TextEdit; | 20 | use 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)] | ||
121 | pub struct LocatedImport { | ||
122 | import_path: ModPath, | ||
123 | item_to_import: ItemInNs, | ||
124 | import_display_override: Option<(ModPath, ItemInNs)>, | ||
125 | } | ||
126 | |||
127 | impl 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 | |||
120 | impl ImportAssets { | 156 | impl 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 | ||
232 | fn path_applicable_items<'a>( | 258 | fn 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 | ||
339 | fn trait_applicable_defs<'a>( | 368 | fn 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 | ||
401 | fn get_mod_path( | 440 | fn 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 | ||
18 | pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; | 18 | pub(crate) const DEFAULT_QUERY_SEARCH_LIMIT: usize = 40; |
19 | 19 | ||
20 | pub fn find_exact_imports<'a>( | 20 | pub 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 | ||
50 | pub fn find_similar_imports<'a>( | 50 | pub 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(), |