diff options
-rw-r--r-- | crates/hir_def/src/import_map.rs | 23 | ||||
-rw-r--r-- | crates/ide/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/auto_import.rs | 13 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/qualify_path.rs | 22 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs | 10 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 101 | ||||
-rw-r--r-- | crates/ide_completion/src/item.rs | 43 | ||||
-rw-r--r-- | crates/ide_completion/src/lib.rs | 17 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 14 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 155 | ||||
-rw-r--r-- | crates/ide_db/src/items_locator.rs (renamed from crates/ide_db/src/imports_locator.rs) | 75 | ||||
-rw-r--r-- | crates/ide_db/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 5 |
13 files changed, 243 insertions, 239 deletions
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 369bc3350..07ee7bdfd 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -1094,4 +1094,27 @@ mod tests { | |||
1094 | expect![[r#""#]], | 1094 | expect![[r#""#]], |
1095 | ); | 1095 | ); |
1096 | } | 1096 | } |
1097 | |||
1098 | #[test] | ||
1099 | fn search_with_path() { | ||
1100 | check_search( | ||
1101 | r#" | ||
1102 | //- /main.rs crate:main deps:dep | ||
1103 | //- /dep.rs crate:dep | ||
1104 | pub mod foo { | ||
1105 | pub mod bar { | ||
1106 | pub mod baz { | ||
1107 | pub trait Display { | ||
1108 | fn fmt(); | ||
1109 | } | ||
1110 | } | ||
1111 | } | ||
1112 | }"#, | ||
1113 | "main", | ||
1114 | Query::new("baz::fmt".to_string()).search_mode(SearchMode::Fuzzy), | ||
1115 | expect![[r#" | ||
1116 | dep::foo::bar::baz::Display::fmt (a) | ||
1117 | "#]], | ||
1118 | ); | ||
1119 | } | ||
1097 | } | 1120 | } |
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs index b600178ee..f83ed65d5 100644 --- a/crates/ide/src/lib.rs +++ b/crates/ide/src/lib.rs | |||
@@ -478,7 +478,6 @@ impl Analysis { | |||
478 | position: FilePosition, | 478 | position: FilePosition, |
479 | full_import_path: &str, | 479 | full_import_path: &str, |
480 | imported_name: String, | 480 | imported_name: String, |
481 | import_for_trait_assoc_item: bool, | ||
482 | ) -> Cancelable<Vec<TextEdit>> { | 481 | ) -> Cancelable<Vec<TextEdit>> { |
483 | Ok(self | 482 | Ok(self |
484 | .with_db(|db| { | 483 | .with_db(|db| { |
@@ -488,7 +487,6 @@ impl Analysis { | |||
488 | position, | 487 | position, |
489 | full_import_path, | 488 | full_import_path, |
490 | imported_name, | 489 | imported_name, |
491 | import_for_trait_assoc_item, | ||
492 | ) | 490 | ) |
493 | })? | 491 | })? |
494 | .unwrap_or_default()) | 492 | .unwrap_or_default()) |
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs index 182547589..f3c969eee 100644 --- a/crates/ide_assists/src/handlers/auto_import.rs +++ b/crates/ide_assists/src/handlers/auto_import.rs | |||
@@ -93,17 +93,18 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
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 | let name = match import.original_item_name(ctx.db()) { | ||
97 | Some(name) => name, | ||
98 | None => continue, | ||
99 | }; | ||
96 | acc.add_group( | 100 | acc.add_group( |
97 | &group, | 101 | &group, |
98 | AssistId("auto_import", AssistKind::QuickFix), | 102 | AssistId("auto_import", AssistKind::QuickFix), |
99 | format!("Import `{}`", import.display_path()), | 103 | format!("Import `{}`", name), |
100 | range, | 104 | range, |
101 | |builder| { | 105 | |builder| { |
102 | let rewriter = insert_use( | 106 | let rewriter = |
103 | &scope, | 107 | insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); |
104 | mod_path_to_ast(import.import_path()), | ||
105 | ctx.config.insert_use, | ||
106 | ); | ||
107 | builder.rewrite(rewriter); | 108 | builder.rewrite(rewriter); |
108 | }, | 109 | }, |
109 | ); | 110 | ); |
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs index 261178448..407ba47be 100644 --- a/crates/ide_assists/src/handlers/qualify_path.rs +++ b/crates/ide_assists/src/handlers/qualify_path.rs | |||
@@ -2,7 +2,7 @@ use std::iter; | |||
2 | 2 | ||
3 | use hir::AsAssocItem; | 3 | use hir::AsAssocItem; |
4 | use ide_db::helpers::{ | 4 | use ide_db::helpers::{ |
5 | import_assets::{ImportCandidate, Qualifier}, | 5 | import_assets::{ImportCandidate, LocatedImport, Qualifier}, |
6 | mod_path_to_ast, | 6 | mod_path_to_ast, |
7 | }; | 7 | }; |
8 | use ide_db::RootDatabase; | 8 | use ide_db::RootDatabase; |
@@ -78,13 +78,13 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
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.display_path()), | 81 | label(ctx.db(), candidate, &import), |
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.import_path(), | 86 | &import.import_path, |
87 | import.item_to_import(), | 87 | import.item_to_import, |
88 | ) | 88 | ) |
89 | }, | 89 | }, |
90 | ); | 90 | ); |
@@ -197,17 +197,21 @@ fn group_label(candidate: &ImportCandidate) -> GroupLabel { | |||
197 | GroupLabel(format!("Qualify {}", name)) | 197 | GroupLabel(format!("Qualify {}", name)) |
198 | } | 198 | } |
199 | 199 | ||
200 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { | 200 | fn label(db: &RootDatabase, candidate: &ImportCandidate, import: &LocatedImport) -> String { |
201 | let display_path = match import.original_item_name(db) { | ||
202 | Some(display_path) => display_path.to_string(), | ||
203 | None => "{unknown}".to_string(), | ||
204 | }; | ||
201 | match candidate { | 205 | match candidate { |
202 | ImportCandidate::Path(candidate) => { | 206 | ImportCandidate::Path(candidate) => { |
203 | if !matches!(candidate.qualifier, Qualifier::Absent) { | 207 | if !matches!(candidate.qualifier, Qualifier::Absent) { |
204 | format!("Qualify with `{}`", &import) | 208 | format!("Qualify with `{}`", display_path) |
205 | } else { | 209 | } else { |
206 | format!("Qualify as `{}`", &import) | 210 | format!("Qualify as `{}`", display_path) |
207 | } | 211 | } |
208 | } | 212 | } |
209 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), | 213 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", display_path), |
210 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), | 214 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", display_path), |
211 | } | 215 | } |
212 | } | 216 | } |
213 | 217 | ||
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs index c69bc5cac..93a03e8b2 100644 --- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | use hir::ModuleDef; | ||
1 | use ide_db::helpers::mod_path_to_ast; | 2 | use ide_db::helpers::mod_path_to_ast; |
2 | use ide_db::imports_locator; | 3 | use ide_db::items_locator; |
3 | use itertools::Itertools; | 4 | use itertools::Itertools; |
4 | use syntax::{ | 5 | use syntax::{ |
5 | ast::{self, make, AstNode, NameOwner}, | 6 | ast::{self, make, AstNode, NameOwner}, |
@@ -64,13 +65,14 @@ pub(crate) fn replace_derive_with_manual_impl( | |||
64 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; | 65 | let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; |
65 | let current_crate = current_module.krate(); | 66 | let current_crate = current_module.krate(); |
66 | 67 | ||
67 | let found_traits = imports_locator::find_exact_imports( | 68 | let found_traits = items_locator::with_for_exact_name( |
68 | &ctx.sema, | 69 | &ctx.sema, |
69 | current_crate, | 70 | current_crate, |
70 | trait_token.text().to_string(), | 71 | trait_token.text().to_string(), |
71 | ) | 72 | ) |
72 | .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate { | 73 | .into_iter() |
73 | either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_), | 74 | .filter_map(|item| match ModuleDef::from(item.as_module_def_id()?) { |
75 | ModuleDef::Trait(trait_) => Some(trait_), | ||
74 | _ => None, | 76 | _ => None, |
75 | }) | 77 | }) |
76 | .flat_map(|trait_| { | 78 | .flat_map(|trait_| { |
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 1ef6f8afb..c1e3f091f 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -87,11 +87,12 @@ | |||
87 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | 87 | //! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding |
88 | //! capability enabled. | 88 | //! capability enabled. |
89 | 89 | ||
90 | use hir::{AsAssocItem, ModPath, ModuleDef, ScopeDef}; | 90 | use hir::ModPath; |
91 | use ide_db::helpers::{ | 91 | use ide_db::helpers::{ |
92 | import_assets::{ImportAssets, ImportCandidate}, | 92 | import_assets::{ImportAssets, ImportCandidate}, |
93 | insert_use::ImportScope, | 93 | insert_use::ImportScope, |
94 | }; | 94 | }; |
95 | use itertools::Itertools; | ||
95 | use syntax::{AstNode, SyntaxNode, T}; | 96 | use syntax::{AstNode, SyntaxNode, T}; |
96 | 97 | ||
97 | use crate::{ | 98 | use crate::{ |
@@ -130,27 +131,23 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
130 | &ctx.sema, | 131 | &ctx.sema, |
131 | )?; | 132 | )?; |
132 | 133 | ||
133 | let mut all_imports = | 134 | acc.add_all( |
134 | import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind); | 135 | import_assets |
135 | all_imports.sort_by_cached_key(|import| { | 136 | .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) |
136 | compute_fuzzy_completion_order_key(import.display_path(), &user_input_lowercased) | 137 | .into_iter() |
137 | }); | 138 | .sorted_by_key(|located_import| { |
138 | 139 | compute_fuzzy_completion_order_key( | |
139 | acc.add_all(all_imports.into_iter().filter_map(|import| { | 140 | &located_import.import_path, |
140 | let import_for_trait_assoc_item = import | 141 | &user_input_lowercased, |
141 | .item_to_display() | 142 | ) |
142 | .as_module_def_id() | ||
143 | .and_then(|module_def_id| { | ||
144 | ModuleDef::from(module_def_id).as_assoc_item(ctx.db)?.containing_trait(ctx.db) | ||
145 | }) | 143 | }) |
146 | .is_some(); | 144 | .filter_map(|import| { |
147 | let def_to_display = ScopeDef::from(import.item_to_display()); | 145 | render_resolution_with_import( |
148 | render_resolution_with_import( | 146 | RenderContext::new(ctx), |
149 | RenderContext::new(ctx), | 147 | ImportEdit { import, import_scope: import_scope.clone() }, |
150 | ImportEdit { import, import_scope: import_scope.clone(), import_for_trait_assoc_item }, | 148 | ) |
151 | &def_to_display, | 149 | }), |
152 | ) | 150 | ); |
153 | })); | ||
154 | Some(()) | 151 | Some(()) |
155 | } | 152 | } |
156 | 153 | ||
@@ -190,6 +187,7 @@ fn import_assets<'a>(ctx: &'a CompletionContext, fuzzy_name: String) -> Option<I | |||
190 | ctx.scope.clone(), | 187 | ctx.scope.clone(), |
191 | )?; | 188 | )?; |
192 | 189 | ||
190 | // TODO kb bad: with the path prefix, the "min 3 symbols" limit applies. Fix in a separate PR on the symbol_index level | ||
193 | if matches!(assets_for_path.import_candidate(), ImportCandidate::Path(_)) | 191 | if matches!(assets_for_path.import_candidate(), ImportCandidate::Path(_)) |
194 | && fuzzy_name_length < 2 | 192 | && fuzzy_name_length < 2 |
195 | { | 193 | { |
@@ -796,9 +794,7 @@ fn main() { | |||
796 | 794 | ||
797 | #[test] | 795 | #[test] |
798 | fn unresolved_qualifier() { | 796 | fn unresolved_qualifier() { |
799 | check_edit( | 797 | let fixture = r#" |
800 | "Item", | ||
801 | r#" | ||
802 | mod foo { | 798 | mod foo { |
803 | pub mod bar { | 799 | pub mod bar { |
804 | pub mod baz { | 800 | pub mod baz { |
@@ -809,31 +805,34 @@ mod foo { | |||
809 | 805 | ||
810 | fn main() { | 806 | fn main() { |
811 | bar::baz::Ite$0 | 807 | bar::baz::Ite$0 |
812 | } | 808 | }"#; |
813 | "#, | 809 | |
810 | check(fixture, expect![["st Item (foo::bar::baz::Item)"]]); | ||
811 | |||
812 | check_edit( | ||
813 | "Item", | ||
814 | fixture, | ||
814 | r#" | 815 | r#" |
815 | use foo::bar; | 816 | use foo::bar; |
816 | 817 | ||
817 | mod foo { | 818 | mod foo { |
818 | pub mod bar { | 819 | pub mod bar { |
819 | pub mod baz { | 820 | pub mod baz { |
820 | pub struct Item; | 821 | pub struct Item; |
822 | } | ||
823 | } | ||
821 | } | 824 | } |
822 | } | ||
823 | } | ||
824 | 825 | ||
825 | fn main() { | 826 | fn main() { |
826 | bar::baz::Item | 827 | bar::baz::Item |
827 | } | 828 | } |
828 | "#, | 829 | "#, |
829 | ); | 830 | ); |
830 | } | 831 | } |
831 | 832 | ||
832 | #[test] | 833 | #[test] |
833 | fn unresolved_assoc_item_container() { | 834 | fn unresolved_assoc_item_container() { |
834 | check_edit( | 835 | let fixture = r#" |
835 | "TEST_ASSOC", | ||
836 | r#" | ||
837 | mod foo { | 836 | mod foo { |
838 | pub struct Item; | 837 | pub struct Item; |
839 | 838 | ||
@@ -844,8 +843,13 @@ mod foo { | |||
844 | 843 | ||
845 | fn main() { | 844 | fn main() { |
846 | Item::TEST_A$0 | 845 | Item::TEST_A$0 |
847 | } | 846 | }"#; |
848 | "#, | 847 | |
848 | check(fixture, expect![["ct TEST_ASSOC (foo::bar::baz::Item)"]]); | ||
849 | |||
850 | check_edit( | ||
851 | "TEST_ASSOC", | ||
852 | fixture, | ||
849 | r#" | 853 | r#" |
850 | use foo::Item; | 854 | use foo::Item; |
851 | 855 | ||
@@ -866,9 +870,7 @@ fn main() { | |||
866 | 870 | ||
867 | #[test] | 871 | #[test] |
868 | fn unresolved_assoc_item_container_with_path() { | 872 | fn unresolved_assoc_item_container_with_path() { |
869 | check_edit( | 873 | let fixture = r#" |
870 | "TEST_ASSOC", | ||
871 | r#" | ||
872 | mod foo { | 874 | mod foo { |
873 | pub mod bar { | 875 | pub mod bar { |
874 | pub struct Item; | 876 | pub struct Item; |
@@ -881,8 +883,13 @@ mod foo { | |||
881 | 883 | ||
882 | fn main() { | 884 | fn main() { |
883 | bar::Item::TEST_A$0 | 885 | bar::Item::TEST_A$0 |
884 | } | 886 | }"#; |
885 | "#, | 887 | |
888 | check(fixture, expect![["ct TEST_ASSOC (foo::bar::baz::Item)"]]); | ||
889 | |||
890 | check_edit( | ||
891 | "TEST_ASSOC", | ||
892 | fixture, | ||
886 | r#" | 893 | r#" |
887 | use foo::bar; | 894 | use foo::bar; |
888 | 895 | ||
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs index 0390fe226..d01620500 100644 --- a/crates/ide_completion/src/item.rs +++ b/crates/ide_completion/src/item.rs | |||
@@ -275,7 +275,6 @@ impl CompletionItem { | |||
275 | pub struct ImportEdit { | 275 | pub struct ImportEdit { |
276 | pub import: LocatedImport, | 276 | pub import: LocatedImport, |
277 | pub import_scope: ImportScope, | 277 | pub import_scope: ImportScope, |
278 | pub import_for_trait_assoc_item: bool, | ||
279 | } | 278 | } |
280 | 279 | ||
281 | impl ImportEdit { | 280 | impl ImportEdit { |
@@ -286,7 +285,7 @@ impl ImportEdit { | |||
286 | 285 | ||
287 | let rewriter = insert_use::insert_use( | 286 | let rewriter = insert_use::insert_use( |
288 | &self.import_scope, | 287 | &self.import_scope, |
289 | mod_path_to_ast(self.import.import_path()), | 288 | mod_path_to_ast(&self.import.import_path), |
290 | cfg, | 289 | cfg, |
291 | ); | 290 | ); |
292 | let old_ast = rewriter.rewrite_root()?; | 291 | let old_ast = rewriter.rewrite_root()?; |
@@ -303,6 +302,7 @@ impl ImportEdit { | |||
303 | pub(crate) struct Builder { | 302 | pub(crate) struct Builder { |
304 | source_range: TextRange, | 303 | source_range: TextRange, |
305 | completion_kind: CompletionKind, | 304 | completion_kind: CompletionKind, |
305 | // TODO kb also add a db here, to resolve the completion label? | ||
306 | import_to_add: Option<ImportEdit>, | 306 | import_to_add: Option<ImportEdit>, |
307 | label: String, | 307 | label: String, |
308 | insert_text: Option<String>, | 308 | insert_text: Option<String>, |
@@ -322,19 +322,22 @@ impl Builder { | |||
322 | pub(crate) fn build(self) -> CompletionItem { | 322 | pub(crate) fn build(self) -> CompletionItem { |
323 | let _p = profile::span("item::Builder::build"); | 323 | let _p = profile::span("item::Builder::build"); |
324 | 324 | ||
325 | let mut label = self.label; | 325 | let label = self.label; |
326 | let mut lookup = self.lookup; | 326 | let lookup = self.lookup; |
327 | let mut insert_text = self.insert_text; | 327 | let insert_text = self.insert_text; |
328 | 328 | ||
329 | 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())); | 330 | todo!("todo kb") |
331 | insert_text = insert_text.or_else(|| Some(label.clone())); | 331 | // let import = &import_to_add.import; |
332 | let display_path = import_to_add.import.display_path(); | 332 | // let item_to_import = import.item_to_import(); |
333 | if import_to_add.import_for_trait_assoc_item { | 333 | // lookup = lookup.or_else(|| Some(label.clone())); |
334 | label = format!("{} ({})", label, display_path); | 334 | // insert_text = insert_text.or_else(|| Some(label.clone())); |
335 | } else { | 335 | // let display_path = import_to_add.import.display_path(); |
336 | label = display_path.to_string(); | 336 | // if import_to_add.import { |
337 | } | 337 | // label = format!("{} ({})", label, display_path); |
338 | // } else { | ||
339 | // label = display_path.to_string(); | ||
340 | // } | ||
338 | } | 341 | } |
339 | 342 | ||
340 | let text_edit = match self.text_edit { | 343 | let text_edit = match self.text_edit { |
@@ -438,8 +441,8 @@ impl Builder { | |||
438 | } | 441 | } |
439 | } | 442 | } |
440 | 443 | ||
441 | impl<'a> Into<CompletionItem> for Builder { | 444 | // impl<'a> Into<CompletionItem> for Builder { |
442 | fn into(self) -> CompletionItem { | 445 | // fn into(self) -> CompletionItem { |
443 | self.build() | 446 | // self.build() |
444 | } | 447 | // } |
445 | } | 448 | // } |
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs index ca2e5e706..d19368de0 100644 --- a/crates/ide_completion/src/lib.rs +++ b/crates/ide_completion/src/lib.rs | |||
@@ -15,7 +15,7 @@ use completions::flyimport::position_for_import; | |||
15 | use ide_db::{ | 15 | use ide_db::{ |
16 | base_db::FilePosition, | 16 | base_db::FilePosition, |
17 | helpers::{import_assets::LocatedImport, insert_use::ImportScope}, | 17 | helpers::{import_assets::LocatedImport, insert_use::ImportScope}, |
18 | imports_locator, RootDatabase, | 18 | items_locator, RootDatabase, |
19 | }; | 19 | }; |
20 | use text_edit::TextEdit; | 20 | use text_edit::TextEdit; |
21 | 21 | ||
@@ -141,7 +141,6 @@ pub fn resolve_completion_edits( | |||
141 | position: FilePosition, | 141 | position: FilePosition, |
142 | full_import_path: &str, | 142 | full_import_path: &str, |
143 | imported_name: String, | 143 | imported_name: String, |
144 | import_for_trait_assoc_item: bool, | ||
145 | ) -> Option<Vec<TextEdit>> { | 144 | ) -> Option<Vec<TextEdit>> { |
146 | let ctx = CompletionContext::new(db, position, config)?; | 145 | let ctx = CompletionContext::new(db, position, config)?; |
147 | let position_for_import = position_for_import(&ctx, None)?; | 146 | let position_for_import = position_for_import(&ctx, None)?; |
@@ -151,19 +150,17 @@ pub fn resolve_completion_edits( | |||
151 | let current_crate = current_module.krate(); | 150 | let current_crate = current_module.krate(); |
152 | 151 | ||
153 | let (import_path, item_to_import) = | 152 | let (import_path, item_to_import) = |
154 | imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) | 153 | items_locator::with_for_exact_name(&ctx.sema, current_crate, imported_name) |
154 | .into_iter() | ||
155 | .filter_map(|candidate| { | 155 | .filter_map(|candidate| { |
156 | let item: hir::ItemInNs = candidate.either(Into::into, Into::into); | ||
157 | current_module | 156 | current_module |
158 | .find_use_path_prefixed(db, item, config.insert_use.prefix_kind) | 157 | .find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind) |
159 | .zip(Some(item)) | 158 | .zip(Some(candidate)) |
160 | }) | 159 | }) |
161 | .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?; | 160 | .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?; |
162 | let import = LocatedImport::new(import_path, item_to_import, None); | 161 | let import = LocatedImport::new(import_path, item_to_import, item_to_import); |
163 | 162 | ||
164 | ImportEdit { import_path, import_scope, import_for_trait_assoc_item } | 163 | ImportEdit { import, import_scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) |
165 | .to_text_edit(config.insert_use) | ||
166 | .map(|edit| vec![edit]) | ||
167 | } | 164 | } |
168 | 165 | ||
169 | #[cfg(test)] | 166 | #[cfg(test)] |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index 4bddc3957..fae5685e2 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -53,18 +53,20 @@ pub(crate) fn render_resolution<'a>( | |||
53 | pub(crate) fn render_resolution_with_import<'a>( | 53 | pub(crate) fn render_resolution_with_import<'a>( |
54 | ctx: RenderContext<'a>, | 54 | ctx: RenderContext<'a>, |
55 | import_edit: ImportEdit, | 55 | import_edit: ImportEdit, |
56 | resolution: &ScopeDef, | ||
57 | ) -> Option<CompletionItem> { | 56 | ) -> Option<CompletionItem> { |
57 | let resolution = ScopeDef::from(import_edit.import.original_item); | ||
58 | let local_name = match resolution { | 58 | let local_name = match resolution { |
59 | ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), | 59 | ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), |
60 | ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), | 60 | ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), |
61 | ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), | 61 | ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), |
62 | _ => item_name(ctx.db(), import_edit.import.item_to_display())?.to_string(), | 62 | _ => item_name(ctx.db(), import_edit.import.original_item)?.to_string(), |
63 | }; | 63 | }; |
64 | Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| { | 64 | Render::new(ctx).render_resolution(local_name, Some(import_edit), &resolution).map( |
65 | item.completion_kind = CompletionKind::Magic; | 65 | |mut item| { |
66 | item | 66 | item.completion_kind = CompletionKind::Magic; |
67 | }) | 67 | item |
68 | }, | ||
69 | ) | ||
68 | } | 70 | } |
69 | 71 | ||
70 | /// Interface for data and methods required for items rendering. | 72 | /// Interface for data and methods required for items rendering. |
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index a30a4dd9d..8d16c011e 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -1,14 +1,13 @@ | |||
1 | //! Look up accessible paths for items. | 1 | //! Look up accessible paths for items. |
2 | use either::Either; | ||
3 | use hir::{ | 2 | use hir::{ |
4 | AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, | 3 | AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, |
5 | ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type, | 4 | ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type, |
6 | }; | 5 | }; |
7 | use rustc_hash::FxHashSet; | 6 | use rustc_hash::FxHashSet; |
8 | use syntax::{ast, AstNode}; | 7 | use syntax::{ast, AstNode}; |
9 | 8 | ||
10 | use crate::{ | 9 | use crate::{ |
11 | imports_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT}, | 10 | items_locator::{self, AssocItemSearch, DEFAULT_QUERY_SEARCH_LIMIT}, |
12 | RootDatabase, | 11 | RootDatabase, |
13 | }; | 12 | }; |
14 | 13 | ||
@@ -130,34 +129,23 @@ impl<'a> ImportAssets<'a> { | |||
130 | 129 | ||
131 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 130 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
132 | pub struct LocatedImport { | 131 | pub struct LocatedImport { |
133 | import_path: ModPath, | 132 | pub import_path: ModPath, |
134 | item_to_import: ItemInNs, | 133 | pub item_to_import: ItemInNs, |
135 | data_to_display: Option<(ModPath, ItemInNs)>, | 134 | pub original_item: ItemInNs, |
136 | } | 135 | } |
137 | 136 | ||
138 | impl LocatedImport { | 137 | impl LocatedImport { |
139 | pub fn new( | 138 | pub fn new(import_path: ModPath, item_to_import: ItemInNs, original_item: ItemInNs) -> Self { |
140 | import_path: ModPath, | 139 | Self { import_path, item_to_import, original_item } |
141 | item_to_import: ItemInNs, | ||
142 | data_to_display: Option<(ModPath, ItemInNs)>, | ||
143 | ) -> Self { | ||
144 | Self { import_path, item_to_import, data_to_display } | ||
145 | } | 140 | } |
146 | 141 | ||
147 | pub fn display_path(&self) -> &ModPath { | 142 | pub fn original_item_name(&self, db: &RootDatabase) -> Option<Name> { |
148 | self.data_to_display.as_ref().map(|(mod_path, _)| mod_path).unwrap_or(&self.import_path) | 143 | match self.original_item { |
149 | } | 144 | ItemInNs::Types(module_def_id) | ItemInNs::Values(module_def_id) => { |
150 | 145 | ModuleDef::from(module_def_id).name(db) | |
151 | pub fn import_path(&self) -> &ModPath { | 146 | } |
152 | &self.import_path | 147 | ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db), |
153 | } | 148 | } |
154 | |||
155 | pub fn item_to_display(&self) -> ItemInNs { | ||
156 | self.data_to_display.as_ref().map(|&(_, item)| item).unwrap_or(self.item_to_import) | ||
157 | } | ||
158 | |||
159 | pub fn item_to_import(&self) -> ItemInNs { | ||
160 | self.item_to_import | ||
161 | } | 149 | } |
162 | } | 150 | } |
163 | 151 | ||
@@ -166,25 +154,20 @@ impl<'a> ImportAssets<'a> { | |||
166 | &self.import_candidate | 154 | &self.import_candidate |
167 | } | 155 | } |
168 | 156 | ||
169 | fn name_to_import(&self) -> &NameToImport { | ||
170 | match &self.import_candidate { | ||
171 | ImportCandidate::Path(candidate) => &candidate.name, | ||
172 | ImportCandidate::TraitAssocItem(candidate) | ||
173 | | ImportCandidate::TraitMethod(candidate) => &candidate.name, | ||
174 | } | ||
175 | } | ||
176 | |||
177 | pub fn search_for_imports( | 157 | pub fn search_for_imports( |
178 | &self, | 158 | &self, |
179 | sema: &Semantics<RootDatabase>, | 159 | sema: &Semantics<RootDatabase>, |
180 | prefix_kind: PrefixKind, | 160 | prefix_kind: PrefixKind, |
181 | ) -> Vec<LocatedImport> { | 161 | ) -> FxHashSet<LocatedImport> { |
182 | let _p = profile::span("import_assets::search_for_imports"); | 162 | let _p = profile::span("import_assets::search_for_imports"); |
183 | self.search_for(sema, Some(prefix_kind)) | 163 | self.search_for(sema, Some(prefix_kind)) |
184 | } | 164 | } |
185 | 165 | ||
186 | /// This may return non-absolute paths if a part of the returned path is already imported into scope. | 166 | /// This may return non-absolute paths if a part of the returned path is already imported into scope. |
187 | pub fn search_for_relative_paths(&self, sema: &Semantics<RootDatabase>) -> Vec<LocatedImport> { | 167 | pub fn search_for_relative_paths( |
168 | &self, | ||
169 | sema: &Semantics<RootDatabase>, | ||
170 | ) -> FxHashSet<LocatedImport> { | ||
188 | let _p = profile::span("import_assets::search_for_relative_paths"); | 171 | let _p = profile::span("import_assets::search_for_relative_paths"); |
189 | self.search_for(sema, None) | 172 | self.search_for(sema, None) |
190 | } | 173 | } |
@@ -193,14 +176,13 @@ impl<'a> ImportAssets<'a> { | |||
193 | &self, | 176 | &self, |
194 | sema: &Semantics<RootDatabase>, | 177 | sema: &Semantics<RootDatabase>, |
195 | prefixed: Option<PrefixKind>, | 178 | prefixed: Option<PrefixKind>, |
196 | ) -> Vec<LocatedImport> { | 179 | ) -> FxHashSet<LocatedImport> { |
197 | let current_crate = self.module_with_candidate.krate(); | 180 | let items_with_candidate_name = match self.name_to_import() { |
198 | let scope_definitions = self.scope_definitions(); | 181 | NameToImport::Exact(exact_name) => items_locator::with_for_exact_name( |
199 | 182 | sema, | |
200 | let defs_for_candidate_name = match self.name_to_import() { | 183 | self.module_with_candidate.krate(), |
201 | NameToImport::Exact(exact_name) => { | 184 | exact_name.clone(), |
202 | imports_locator::find_exact_imports(sema, current_crate, exact_name.clone()) | 185 | ), |
203 | } | ||
204 | // FIXME: ideally, we should avoid using `fst` for seacrhing trait imports for assoc items: | 186 | // FIXME: ideally, we should avoid using `fst` for seacrhing trait imports for assoc items: |
205 | // instead, we need to look up all trait impls for a certain struct and search through them only | 187 | // instead, we need to look up all trait impls for a certain struct and search through them only |
206 | // see https://github.com/rust-analyzer/rust-analyzer/pull/7293#issuecomment-761585032 | 188 | // see https://github.com/rust-analyzer/rust-analyzer/pull/7293#issuecomment-761585032 |
@@ -213,9 +195,9 @@ impl<'a> ImportAssets<'a> { | |||
213 | (AssocItemSearch::Include, Some(DEFAULT_QUERY_SEARCH_LIMIT)) | 195 | (AssocItemSearch::Include, Some(DEFAULT_QUERY_SEARCH_LIMIT)) |
214 | }; | 196 | }; |
215 | 197 | ||
216 | imports_locator::find_similar_imports( | 198 | items_locator::with_similar_name( |
217 | sema, | 199 | sema, |
218 | current_crate, | 200 | self.module_with_candidate.krate(), |
219 | fuzzy_name.clone(), | 201 | fuzzy_name.clone(), |
220 | assoc_item_search, | 202 | assoc_item_search, |
221 | limit, | 203 | limit, |
@@ -223,10 +205,11 @@ impl<'a> ImportAssets<'a> { | |||
223 | } | 205 | } |
224 | }; | 206 | }; |
225 | 207 | ||
226 | self.applicable_defs(sema.db, prefixed, defs_for_candidate_name) | 208 | let scope_definitions = self.scope_definitions(); |
209 | self.applicable_defs(sema.db, prefixed, items_with_candidate_name) | ||
227 | .into_iter() | 210 | .into_iter() |
228 | .filter(|import| import.import_path().len() > 1) | 211 | .filter(|import| import.import_path.len() > 1) |
229 | .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import()))) | 212 | .filter(|import| !scope_definitions.contains(&ScopeDef::from(import.item_to_import))) |
230 | .collect() | 213 | .collect() |
231 | } | 214 | } |
232 | 215 | ||
@@ -238,11 +221,19 @@ impl<'a> ImportAssets<'a> { | |||
238 | scope_definitions | 221 | scope_definitions |
239 | } | 222 | } |
240 | 223 | ||
224 | fn name_to_import(&self) -> &NameToImport { | ||
225 | match &self.import_candidate { | ||
226 | ImportCandidate::Path(candidate) => &candidate.name, | ||
227 | ImportCandidate::TraitAssocItem(candidate) | ||
228 | | ImportCandidate::TraitMethod(candidate) => &candidate.name, | ||
229 | } | ||
230 | } | ||
231 | |||
241 | fn applicable_defs( | 232 | fn applicable_defs( |
242 | &self, | 233 | &self, |
243 | db: &RootDatabase, | 234 | db: &RootDatabase, |
244 | prefixed: Option<PrefixKind>, | 235 | prefixed: Option<PrefixKind>, |
245 | defs_for_candidate_name: impl Iterator<Item = Either<ModuleDef, MacroDef>>, | 236 | items_with_candidate_name: FxHashSet<ItemInNs>, |
246 | ) -> FxHashSet<LocatedImport> { | 237 | ) -> FxHashSet<LocatedImport> { |
247 | let _p = profile::span("import_assets::applicable_defs"); | 238 | let _p = profile::span("import_assets::applicable_defs"); |
248 | let current_crate = self.module_with_candidate.krate(); | 239 | let current_crate = self.module_with_candidate.krate(); |
@@ -251,7 +242,7 @@ impl<'a> ImportAssets<'a> { | |||
251 | 242 | ||
252 | match &self.import_candidate { | 243 | match &self.import_candidate { |
253 | ImportCandidate::Path(path_candidate) => { | 244 | ImportCandidate::Path(path_candidate) => { |
254 | path_applicable_imports(db, path_candidate, mod_path, defs_for_candidate_name) | 245 | path_applicable_imports(db, path_candidate, mod_path, items_with_candidate_name) |
255 | } | 246 | } |
256 | ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items( | 247 | ImportCandidate::TraitAssocItem(trait_candidate) => trait_applicable_items( |
257 | db, | 248 | db, |
@@ -259,7 +250,7 @@ impl<'a> ImportAssets<'a> { | |||
259 | trait_candidate, | 250 | trait_candidate, |
260 | true, | 251 | true, |
261 | mod_path, | 252 | mod_path, |
262 | defs_for_candidate_name, | 253 | items_with_candidate_name, |
263 | ), | 254 | ), |
264 | ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items( | 255 | ImportCandidate::TraitMethod(trait_candidate) => trait_applicable_items( |
265 | db, | 256 | db, |
@@ -267,7 +258,7 @@ impl<'a> ImportAssets<'a> { | |||
267 | trait_candidate, | 258 | trait_candidate, |
268 | false, | 259 | false, |
269 | mod_path, | 260 | mod_path, |
270 | defs_for_candidate_name, | 261 | items_with_candidate_name, |
271 | ), | 262 | ), |
272 | } | 263 | } |
273 | } | 264 | } |
@@ -277,17 +268,15 @@ fn path_applicable_imports( | |||
277 | db: &RootDatabase, | 268 | db: &RootDatabase, |
278 | path_candidate: &PathImportCandidate, | 269 | path_candidate: &PathImportCandidate, |
279 | mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy, | 270 | mod_path: impl Fn(ItemInNs) -> Option<ModPath> + Copy, |
280 | defs_for_candidate_name: impl Iterator<Item = Either<ModuleDef, MacroDef>>, | 271 | items_with_candidate_name: FxHashSet<ItemInNs>, |
281 | ) -> FxHashSet<LocatedImport> { | 272 | ) -> FxHashSet<LocatedImport> { |
282 | let _p = profile::span("import_assets::path_applicable_imports"); | 273 | let _p = profile::span("import_assets::path_applicable_imports"); |
283 | 274 | ||
284 | let items_for_candidate_name = | ||
285 | defs_for_candidate_name.map(|def| def.either(ItemInNs::from, ItemInNs::from)); | ||
286 | |||
287 | let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { | 275 | let (unresolved_first_segment, unresolved_qualifier) = match &path_candidate.qualifier { |
288 | Qualifier::Absent => { | 276 | Qualifier::Absent => { |
289 | return items_for_candidate_name | 277 | return items_with_candidate_name |
290 | .filter_map(|item| Some(LocatedImport::new(mod_path(item)?, item, None))) | 278 | .into_iter() |
279 | .filter_map(|item| Some(LocatedImport::new(mod_path(item)?, item, item))) | ||
291 | .collect(); | 280 | .collect(); |
292 | } | 281 | } |
293 | Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => { | 282 | Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => { |
@@ -295,7 +284,8 @@ fn path_applicable_imports( | |||
295 | } | 284 | } |
296 | }; | 285 | }; |
297 | 286 | ||
298 | items_for_candidate_name | 287 | items_with_candidate_name |
288 | .into_iter() | ||
299 | .filter_map(|item| { | 289 | .filter_map(|item| { |
300 | import_for_item(db, mod_path, &unresolved_first_segment, &unresolved_qualifier, item) | 290 | import_for_item(db, mod_path, &unresolved_first_segment, &unresolved_qualifier, item) |
301 | }) | 291 | }) |
@@ -336,7 +326,6 @@ fn import_for_item( | |||
336 | } | 326 | } |
337 | 327 | ||
338 | let segment_import = find_import_for_segment(db, item_candidate, &unresolved_first_segment)?; | 328 | let segment_import = find_import_for_segment(db, item_candidate, &unresolved_first_segment)?; |
339 | let data_to_display = Some((import_path_candidate.clone(), original_item)); | ||
340 | Some(match (segment_import == item_candidate, trait_to_import) { | 329 | Some(match (segment_import == item_candidate, trait_to_import) { |
341 | (true, Some(_)) => { | 330 | (true, Some(_)) => { |
342 | // FIXME we should be able to import both the trait and the segment, | 331 | // FIXME we should be able to import both the trait and the segment, |
@@ -345,11 +334,11 @@ fn import_for_item( | |||
345 | return None; | 334 | return None; |
346 | } | 335 | } |
347 | (false, Some(trait_to_import)) => { | 336 | (false, Some(trait_to_import)) => { |
348 | LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, data_to_display) | 337 | LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, original_item) |
349 | } | 338 | } |
350 | (true, None) => LocatedImport::new(import_path_candidate, item_candidate, data_to_display), | 339 | (true, None) => LocatedImport::new(import_path_candidate, item_candidate, original_item), |
351 | (false, None) => { | 340 | (false, None) => { |
352 | LocatedImport::new(mod_path(segment_import)?, segment_import, data_to_display) | 341 | LocatedImport::new(mod_path(segment_import)?, segment_import, original_item) |
353 | } | 342 | } |
354 | }) | 343 | }) |
355 | } | 344 | } |
@@ -399,16 +388,14 @@ fn trait_applicable_items( | |||
399 | trait_candidate: &TraitImportCandidate, | 388 | trait_candidate: &TraitImportCandidate, |
400 | trait_assoc_item: bool, | 389 | trait_assoc_item: bool, |
401 | mod_path: impl Fn(ItemInNs) -> Option<ModPath>, | 390 | mod_path: impl Fn(ItemInNs) -> Option<ModPath>, |
402 | defs_for_candidate_name: impl Iterator<Item = Either<ModuleDef, MacroDef>>, | 391 | items_with_candidate_name: FxHashSet<ItemInNs>, |
403 | ) -> FxHashSet<LocatedImport> { | 392 | ) -> FxHashSet<LocatedImport> { |
404 | let _p = profile::span("import_assets::trait_applicable_items"); | 393 | let _p = profile::span("import_assets::trait_applicable_items"); |
405 | let mut required_assoc_items = FxHashSet::default(); | 394 | let mut required_assoc_items = FxHashSet::default(); |
406 | 395 | ||
407 | let trait_candidates = defs_for_candidate_name | 396 | let trait_candidates = items_with_candidate_name |
408 | .filter_map(|input| match input { | 397 | .into_iter() |
409 | Either::Left(module_def) => module_def.as_assoc_item(db), | 398 | .filter_map(|input| ModuleDef::from(input.as_module_def_id()?).as_assoc_item(db)) |
410 | _ => None, | ||
411 | }) | ||
412 | .filter_map(|assoc| { | 399 | .filter_map(|assoc| { |
413 | let assoc_item_trait = assoc.containing_trait(db)?; | 400 | let assoc_item_trait = assoc.containing_trait(db)?; |
414 | required_assoc_items.insert(assoc); | 401 | required_assoc_items.insert(assoc); |
@@ -433,20 +420,10 @@ fn trait_applicable_items( | |||
433 | } | 420 | } |
434 | 421 | ||
435 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); | 422 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); |
436 | let item_path = mod_path(item)?; | ||
437 | |||
438 | let assoc_item = assoc_to_item(assoc); | ||
439 | let assoc_item_path = match assoc.container(db) { | ||
440 | AssocItemContainer::Trait(_) => item_path.clone(), | ||
441 | AssocItemContainer::Impl(impl_) => mod_path(ItemInNs::from( | ||
442 | ModuleDef::from(impl_.target_ty(db).as_adt()?), | ||
443 | ))?, | ||
444 | }; | ||
445 | |||
446 | located_imports.insert(LocatedImport::new( | 423 | located_imports.insert(LocatedImport::new( |
447 | item_path, | 424 | mod_path(item)?, |
448 | item, | 425 | item, |
449 | Some((assoc_item_path, assoc_item)), | 426 | assoc_to_item(assoc), |
450 | )); | 427 | )); |
451 | } | 428 | } |
452 | None::<()> | 429 | None::<()> |
@@ -462,20 +439,10 @@ fn trait_applicable_items( | |||
462 | let assoc = function.as_assoc_item(db)?; | 439 | let assoc = function.as_assoc_item(db)?; |
463 | if required_assoc_items.contains(&assoc) { | 440 | if required_assoc_items.contains(&assoc) { |
464 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); | 441 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); |
465 | let item_path = mod_path(item)?; | ||
466 | |||
467 | let assoc_item = assoc_to_item(assoc); | ||
468 | let assoc_item_path = match assoc.container(db) { | ||
469 | AssocItemContainer::Trait(_) => item_path.clone(), | ||
470 | AssocItemContainer::Impl(impl_) => mod_path(ItemInNs::from( | ||
471 | ModuleDef::from(impl_.target_ty(db).as_adt()?), | ||
472 | ))?, | ||
473 | }; | ||
474 | |||
475 | located_imports.insert(LocatedImport::new( | 442 | located_imports.insert(LocatedImport::new( |
476 | item_path, | 443 | mod_path(item)?, |
477 | item, | 444 | item, |
478 | Some((assoc_item_path, assoc_item)), | 445 | assoc_to_item(assoc), |
479 | )); | 446 | )); |
480 | } | 447 | } |
481 | None::<()> | 448 | None::<()> |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/items_locator.rs index fd700e04f..b81c14618 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/items_locator.rs | |||
@@ -1,9 +1,10 @@ | |||
1 | //! This module contains an import search functionality that is provided to the assists module. | 1 | //! This module contains an import search functionality that is provided to the assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. |
3 | 3 | ||
4 | use either::Either; | ||
4 | use hir::{ | 5 | use hir::{ |
5 | import_map::{self, ImportKind}, | 6 | import_map::{self, ImportKind}, |
6 | AsAssocItem, Crate, MacroDef, ModuleDef, Semantics, | 7 | AsAssocItem, Crate, ItemInNs, ModuleDef, Semantics, |
7 | }; | 8 | }; |
8 | use syntax::{ast, AstNode, SyntaxKind::NAME}; | 9 | use syntax::{ast, AstNode, SyntaxKind::NAME}; |
9 | 10 | ||
@@ -12,32 +13,31 @@ use crate::{ | |||
12 | symbol_index::{self, FileSymbol}, | 13 | symbol_index::{self, FileSymbol}, |
13 | RootDatabase, | 14 | RootDatabase, |
14 | }; | 15 | }; |
15 | use either::Either; | ||
16 | use rustc_hash::FxHashSet; | 16 | 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( | 20 | pub fn with_for_exact_name( |
21 | sema: &Semantics<'_, RootDatabase>, | 21 | sema: &Semantics<'_, RootDatabase>, |
22 | krate: Crate, | 22 | krate: Crate, |
23 | name_to_import: String, | 23 | exact_name: String, |
24 | ) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>>> { | 24 | ) -> FxHashSet<ItemInNs> { |
25 | let _p = profile::span("find_exact_imports"); | 25 | let _p = profile::span("find_exact_imports"); |
26 | Box::new(find_imports( | 26 | find_items( |
27 | sema, | 27 | sema, |
28 | krate, | 28 | krate, |
29 | { | 29 | { |
30 | let mut local_query = symbol_index::Query::new(name_to_import.clone()); | 30 | let mut local_query = symbol_index::Query::new(exact_name.clone()); |
31 | local_query.exact(); | 31 | local_query.exact(); |
32 | local_query.limit(DEFAULT_QUERY_SEARCH_LIMIT); | 32 | local_query.limit(DEFAULT_QUERY_SEARCH_LIMIT); |
33 | local_query | 33 | local_query |
34 | }, | 34 | }, |
35 | import_map::Query::new(name_to_import) | 35 | import_map::Query::new(exact_name) |
36 | .limit(DEFAULT_QUERY_SEARCH_LIMIT) | 36 | .limit(DEFAULT_QUERY_SEARCH_LIMIT) |
37 | .name_only() | 37 | .name_only() |
38 | .search_mode(import_map::SearchMode::Equals) | 38 | .search_mode(import_map::SearchMode::Equals) |
39 | .case_sensitive(), | 39 | .case_sensitive(), |
40 | )) | 40 | ) |
41 | } | 41 | } |
42 | 42 | ||
43 | #[derive(Debug)] | 43 | #[derive(Debug)] |
@@ -47,13 +47,13 @@ pub enum AssocItemSearch { | |||
47 | AssocItemsOnly, | 47 | AssocItemsOnly, |
48 | } | 48 | } |
49 | 49 | ||
50 | pub fn find_similar_imports<'a>( | 50 | pub fn with_similar_name( |
51 | sema: &'a Semantics<'a, RootDatabase>, | 51 | sema: &Semantics<'_, 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, |
55 | limit: Option<usize>, | 55 | limit: Option<usize>, |
56 | ) -> Box<dyn Iterator<Item = Either<ModuleDef, MacroDef>> + 'a> { | 56 | ) -> FxHashSet<ItemInNs> { |
57 | let _p = profile::span("find_similar_imports"); | 57 | let _p = profile::span("find_similar_imports"); |
58 | 58 | ||
59 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) | 59 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) |
@@ -77,36 +77,39 @@ pub fn find_similar_imports<'a>( | |||
77 | local_query.limit(limit); | 77 | local_query.limit(limit); |
78 | } | 78 | } |
79 | 79 | ||
80 | Box::new(find_imports(sema, krate, local_query, external_query).filter( | 80 | find_items(sema, krate, local_query, external_query) |
81 | move |import_candidate| match assoc_item_search { | 81 | .into_iter() |
82 | .filter(move |&item| match assoc_item_search { | ||
82 | AssocItemSearch::Include => true, | 83 | AssocItemSearch::Include => true, |
83 | AssocItemSearch::Exclude => !is_assoc_item(import_candidate, sema.db), | 84 | AssocItemSearch::Exclude => !is_assoc_item(item, sema.db), |
84 | AssocItemSearch::AssocItemsOnly => is_assoc_item(import_candidate, sema.db), | 85 | AssocItemSearch::AssocItemsOnly => is_assoc_item(item, sema.db), |
85 | }, | 86 | }) |
86 | )) | 87 | .collect() |
87 | } | 88 | } |
88 | 89 | ||
89 | fn is_assoc_item(import_candidate: &Either<ModuleDef, MacroDef>, db: &RootDatabase) -> bool { | 90 | fn is_assoc_item(item: ItemInNs, db: &RootDatabase) -> bool { |
90 | match import_candidate { | 91 | item.as_module_def_id() |
91 | Either::Left(ModuleDef::Function(function)) => function.as_assoc_item(db).is_some(), | 92 | .and_then(|module_def_id| ModuleDef::from(module_def_id).as_assoc_item(db)) |
92 | Either::Left(ModuleDef::Const(const_)) => const_.as_assoc_item(db).is_some(), | 93 | .is_some() |
93 | Either::Left(ModuleDef::TypeAlias(type_alias)) => type_alias.as_assoc_item(db).is_some(), | ||
94 | _ => false, | ||
95 | } | ||
96 | } | 94 | } |
97 | 95 | ||
98 | fn find_imports<'a>( | 96 | fn find_items( |
99 | sema: &Semantics<'a, RootDatabase>, | 97 | sema: &Semantics<'_, RootDatabase>, |
100 | krate: Crate, | 98 | krate: Crate, |
101 | local_query: symbol_index::Query, | 99 | local_query: symbol_index::Query, |
102 | external_query: import_map::Query, | 100 | external_query: import_map::Query, |
103 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 101 | ) -> FxHashSet<ItemInNs> { |
104 | let _p = profile::span("find_similar_imports"); | 102 | let _p = profile::span("find_similar_imports"); |
105 | let db = sema.db; | 103 | let db = sema.db; |
106 | 104 | ||
107 | // Query dependencies first. | 105 | // Query dependencies first. |
108 | let mut candidates: FxHashSet<_> = | 106 | let mut candidates = krate |
109 | krate.query_external_importables(db, external_query).collect(); | 107 | .query_external_importables(db, external_query) |
108 | .map(|external_importable| match external_importable { | ||
109 | Either::Left(module_def) => ItemInNs::from(module_def), | ||
110 | Either::Right(macro_def) => ItemInNs::from(macro_def), | ||
111 | }) | ||
112 | .collect::<FxHashSet<_>>(); | ||
110 | 113 | ||
111 | // Query the local crate using the symbol index. | 114 | // Query the local crate using the symbol index. |
112 | let local_results = symbol_index::crate_symbols(db, krate.into(), local_query); | 115 | let local_results = symbol_index::crate_symbols(db, krate.into(), local_query); |
@@ -114,19 +117,19 @@ fn find_imports<'a>( | |||
114 | candidates.extend( | 117 | candidates.extend( |
115 | local_results | 118 | local_results |
116 | .into_iter() | 119 | .into_iter() |
117 | .filter_map(|import_candidate| get_name_definition(sema, &import_candidate)) | 120 | .filter_map(|local_candidate| get_name_definition(sema, &local_candidate)) |
118 | .filter_map(|name_definition_to_import| match name_definition_to_import { | 121 | .filter_map(|name_definition_to_import| match name_definition_to_import { |
119 | Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), | 122 | Definition::ModuleDef(module_def) => Some(ItemInNs::from(module_def)), |
120 | Definition::Macro(macro_def) => Some(Either::Right(macro_def)), | 123 | Definition::Macro(macro_def) => Some(ItemInNs::from(macro_def)), |
121 | _ => None, | 124 | _ => None, |
122 | }), | 125 | }), |
123 | ); | 126 | ); |
124 | 127 | ||
125 | candidates.into_iter() | 128 | candidates |
126 | } | 129 | } |
127 | 130 | ||
128 | fn get_name_definition<'a>( | 131 | fn get_name_definition( |
129 | sema: &Semantics<'a, RootDatabase>, | 132 | sema: &Semantics<'_, RootDatabase>, |
130 | import_candidate: &FileSymbol, | 133 | import_candidate: &FileSymbol, |
131 | ) -> Option<Definition> { | 134 | ) -> Option<Definition> { |
132 | let _p = profile::span("get_name_definition"); | 135 | let _p = profile::span("get_name_definition"); |
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 6eb34b06b..88ee4a87d 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs | |||
@@ -8,7 +8,7 @@ pub mod line_index; | |||
8 | pub mod symbol_index; | 8 | pub mod symbol_index; |
9 | pub mod defs; | 9 | pub mod defs; |
10 | pub mod search; | 10 | pub mod search; |
11 | pub mod imports_locator; | 11 | pub mod items_locator; |
12 | pub mod source_change; | 12 | pub mod source_change; |
13 | pub mod ty_filter; | 13 | pub mod ty_filter; |
14 | pub mod traits; | 14 | pub mod traits; |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index d479d826f..2c4c339cb 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -697,7 +697,6 @@ pub(crate) fn handle_completion_resolve( | |||
697 | FilePosition { file_id, offset }, | 697 | FilePosition { file_id, offset }, |
698 | &resolve_data.full_import_path, | 698 | &resolve_data.full_import_path, |
699 | resolve_data.imported_name, | 699 | resolve_data.imported_name, |
700 | resolve_data.import_for_trait_assoc_item, | ||
701 | )? | 700 | )? |
702 | .into_iter() | 701 | .into_iter() |
703 | .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) | 702 | .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel))) |
@@ -1525,7 +1524,6 @@ struct CompletionResolveData { | |||
1525 | position: lsp_types::TextDocumentPositionParams, | 1524 | position: lsp_types::TextDocumentPositionParams, |
1526 | full_import_path: String, | 1525 | full_import_path: String, |
1527 | imported_name: String, | 1526 | imported_name: String, |
1528 | import_for_trait_assoc_item: bool, | ||
1529 | } | 1527 | } |
1530 | 1528 | ||
1531 | fn fill_resolve_data( | 1529 | fn fill_resolve_data( |
@@ -1534,14 +1532,13 @@ fn fill_resolve_data( | |||
1534 | position: &TextDocumentPositionParams, | 1532 | position: &TextDocumentPositionParams, |
1535 | ) -> Option<()> { | 1533 | ) -> Option<()> { |
1536 | let import_edit = item.import_to_add()?; | 1534 | let import_edit = item.import_to_add()?; |
1537 | let import_path = import_edit.import.import_path(); | 1535 | let import_path = &import_edit.import.import_path; |
1538 | 1536 | ||
1539 | *resolve_data = Some( | 1537 | *resolve_data = Some( |
1540 | to_value(CompletionResolveData { | 1538 | to_value(CompletionResolveData { |
1541 | position: position.to_owned(), | 1539 | position: position.to_owned(), |
1542 | full_import_path: import_path.to_string(), | 1540 | full_import_path: import_path.to_string(), |
1543 | imported_name: import_path.segments().last()?.to_string(), | 1541 | imported_name: import_path.segments().last()?.to_string(), |
1544 | import_for_trait_assoc_item: import_edit.import_for_trait_assoc_item, | ||
1545 | }) | 1542 | }) |
1546 | .unwrap(), | 1543 | .unwrap(), |
1547 | ); | 1544 | ); |