diff options
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 65 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 7 | ||||
-rw-r--r-- | crates/ide_db/src/helpers.rs | 10 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/import_assets.rs | 110 |
4 files changed, 143 insertions, 49 deletions
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs index 8ff76688e..e33fc4b78 100644 --- a/crates/ide_completion/src/completions/flyimport.rs +++ b/crates/ide_completion/src/completions/flyimport.rs | |||
@@ -97,7 +97,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) | |||
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(|import| { | 99 | .map(|import| { |
100 | let proposed_def = match import.item_to_import() { | 100 | let proposed_def = match import.item_to_display() { |
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()), |
@@ -809,7 +809,7 @@ fn main() { | |||
809 | #[test] | 809 | #[test] |
810 | fn unresolved_assoc_item_container() { | 810 | fn unresolved_assoc_item_container() { |
811 | check_edit( | 811 | check_edit( |
812 | "Item", | 812 | "TEST_ASSOC", |
813 | r#" | 813 | r#" |
814 | mod foo { | 814 | mod foo { |
815 | pub struct Item; | 815 | pub struct Item; |
@@ -820,7 +820,7 @@ mod foo { | |||
820 | } | 820 | } |
821 | 821 | ||
822 | fn main() { | 822 | fn main() { |
823 | Item::TEST_A$0; | 823 | Item::TEST_A$0 |
824 | } | 824 | } |
825 | "#, | 825 | "#, |
826 | r#" | 826 | r#" |
@@ -844,7 +844,7 @@ fn main() { | |||
844 | #[test] | 844 | #[test] |
845 | fn unresolved_assoc_item_container_with_path() { | 845 | fn unresolved_assoc_item_container_with_path() { |
846 | check_edit( | 846 | check_edit( |
847 | "Item", | 847 | "TEST_ASSOC", |
848 | r#" | 848 | r#" |
849 | mod foo { | 849 | mod foo { |
850 | pub mod bar { | 850 | pub mod bar { |
@@ -857,7 +857,7 @@ mod foo { | |||
857 | } | 857 | } |
858 | 858 | ||
859 | fn main() { | 859 | fn main() { |
860 | bar::Item::TEST_A$0; | 860 | bar::Item::TEST_A$0 |
861 | } | 861 | } |
862 | "#, | 862 | "#, |
863 | r#" | 863 | r#" |
@@ -879,4 +879,59 @@ fn main() { | |||
879 | "#, | 879 | "#, |
880 | ); | 880 | ); |
881 | } | 881 | } |
882 | |||
883 | #[test] | ||
884 | fn unresolved_assoc_item_container_and_trait_with_path() { | ||
885 | check_edit( | ||
886 | "TEST_ASSOC", | ||
887 | r#" | ||
888 | mod foo { | ||
889 | pub mod bar { | ||
890 | pub trait SomeTrait { | ||
891 | const TEST_ASSOC: usize; | ||
892 | } | ||
893 | } | ||
894 | |||
895 | pub mod baz { | ||
896 | use super::bar::SomeTrait; | ||
897 | |||
898 | pub struct Item; | ||
899 | |||
900 | impl SomeTrait for Item { | ||
901 | const TEST_ASSOC: usize = 3; | ||
902 | } | ||
903 | } | ||
904 | } | ||
905 | |||
906 | fn main() { | ||
907 | baz::Item::TEST_A$0 | ||
908 | } | ||
909 | "#, | ||
910 | r#" | ||
911 | use foo::{bar::SomeTrait, baz}; | ||
912 | |||
913 | mod foo { | ||
914 | pub mod bar { | ||
915 | pub trait SomeTrait { | ||
916 | const TEST_ASSOC: usize; | ||
917 | } | ||
918 | } | ||
919 | |||
920 | pub mod baz { | ||
921 | use super::bar::SomeTrait; | ||
922 | |||
923 | pub struct Item; | ||
924 | |||
925 | impl SomeTrait for Item { | ||
926 | const TEST_ASSOC: usize = 3; | ||
927 | } | ||
928 | } | ||
929 | } | ||
930 | |||
931 | fn main() { | ||
932 | baz::Item::TEST_ASSOC | ||
933 | } | ||
934 | "#, | ||
935 | ); | ||
936 | } | ||
882 | } | 937 | } |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index df26e7642..4bddc3957 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -13,7 +13,10 @@ mod builder_ext; | |||
13 | use hir::{ | 13 | use hir::{ |
14 | AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, | 14 | AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, |
15 | }; | 15 | }; |
16 | use ide_db::{helpers::SnippetCap, RootDatabase, SymbolKind}; | 16 | use ide_db::{ |
17 | helpers::{item_name, SnippetCap}, | ||
18 | RootDatabase, SymbolKind, | ||
19 | }; | ||
17 | use syntax::TextRange; | 20 | use syntax::TextRange; |
18 | 21 | ||
19 | use crate::{ | 22 | use crate::{ |
@@ -56,7 +59,7 @@ pub(crate) fn render_resolution_with_import<'a>( | |||
56 | 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(), |
57 | 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(), |
58 | 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(), |
59 | _ => import_edit.import.display_path().segments().last()?.to_string(), | 62 | _ => item_name(ctx.db(), import_edit.import.item_to_display())?.to_string(), |
60 | }; | 63 | }; |
61 | 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(|mut item| { |
62 | item.completion_kind = CompletionKind::Magic; | 65 | item.completion_kind = CompletionKind::Magic; |
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index 3ff77400b..3c95d3cff 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs | |||
@@ -2,11 +2,19 @@ | |||
2 | pub mod insert_use; | 2 | pub mod insert_use; |
3 | pub mod import_assets; | 3 | pub mod import_assets; |
4 | 4 | ||
5 | use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; | 5 | use hir::{Crate, Enum, ItemInNs, MacroDef, Module, ModuleDef, Name, ScopeDef, Semantics, Trait}; |
6 | use syntax::ast::{self, make}; | 6 | use syntax::ast::{self, make}; |
7 | 7 | ||
8 | use crate::RootDatabase; | 8 | use crate::RootDatabase; |
9 | 9 | ||
10 | pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> { | ||
11 | match item { | ||
12 | ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).name(db), | ||
13 | ItemInNs::Values(module_def_id) => ModuleDef::from(module_def_id).name(db), | ||
14 | ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db), | ||
15 | } | ||
16 | } | ||
17 | |||
10 | /// Converts the mod path struct into its ast representation. | 18 | /// Converts the mod path struct into its ast representation. |
11 | pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { | 19 | pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { |
12 | let _p = profile::span("mod_path_to_ast"); | 20 | let _p = profile::span("mod_path_to_ast"); |
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs index d8bf61aaa..3d79f9771 100644 --- a/crates/ide_db/src/helpers/import_assets.rs +++ b/crates/ide_db/src/helpers/import_assets.rs | |||
@@ -1,8 +1,8 @@ | |||
1 | //! Look up accessible paths for items. | 1 | //! Look up accessible paths for items. |
2 | use either::Either; | 2 | use either::Either; |
3 | use hir::{ | 3 | use hir::{ |
4 | AsAssocItem, AssocItem, Crate, ItemInNs, MacroDef, ModPath, Module, ModuleDef, Name, | 4 | AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, |
5 | PrefixKind, Semantics, | 5 | ModuleDef, PathResolution, PrefixKind, Semantics, Type, |
6 | }; | 6 | }; |
7 | use rustc_hash::FxHashSet; | 7 | use rustc_hash::FxHashSet; |
8 | use syntax::{ast, AstNode}; | 8 | use syntax::{ast, AstNode}; |
@@ -12,6 +12,8 @@ use crate::{ | |||
12 | RootDatabase, | 12 | RootDatabase, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | use super::item_name; | ||
16 | |||
15 | #[derive(Debug)] | 17 | #[derive(Debug)] |
16 | pub enum ImportCandidate { | 18 | pub enum ImportCandidate { |
17 | // A path, qualified (`std::collections::HashMap`) or not (`HashMap`). | 19 | // A path, qualified (`std::collections::HashMap`) or not (`HashMap`). |
@@ -28,7 +30,7 @@ pub enum ImportCandidate { | |||
28 | 30 | ||
29 | #[derive(Debug)] | 31 | #[derive(Debug)] |
30 | pub struct TraitImportCandidate { | 32 | pub struct TraitImportCandidate { |
31 | pub receiver_ty: hir::Type, | 33 | pub receiver_ty: Type, |
32 | pub name: NameToImport, | 34 | pub name: NameToImport, |
33 | } | 35 | } |
34 | 36 | ||
@@ -62,7 +64,7 @@ impl NameToImport { | |||
62 | #[derive(Debug)] | 64 | #[derive(Debug)] |
63 | pub struct ImportAssets { | 65 | pub struct ImportAssets { |
64 | import_candidate: ImportCandidate, | 66 | import_candidate: ImportCandidate, |
65 | module_with_candidate: hir::Module, | 67 | module_with_candidate: Module, |
66 | } | 68 | } |
67 | 69 | ||
68 | impl ImportAssets { | 70 | impl ImportAssets { |
@@ -104,7 +106,7 @@ impl ImportAssets { | |||
104 | 106 | ||
105 | pub fn for_fuzzy_method_call( | 107 | pub fn for_fuzzy_method_call( |
106 | module_with_method_call: Module, | 108 | module_with_method_call: Module, |
107 | receiver_ty: hir::Type, | 109 | receiver_ty: Type, |
108 | fuzzy_method_name: String, | 110 | fuzzy_method_name: String, |
109 | ) -> Option<Self> { | 111 | ) -> Option<Self> { |
110 | Some(Self { | 112 | Some(Self { |
@@ -184,7 +186,7 @@ impl ImportAssets { | |||
184 | fn search_for( | 186 | fn search_for( |
185 | &self, | 187 | &self, |
186 | sema: &Semantics<RootDatabase>, | 188 | sema: &Semantics<RootDatabase>, |
187 | prefixed: Option<hir::PrefixKind>, | 189 | prefixed: Option<PrefixKind>, |
188 | ) -> Vec<LocatedImport> { | 190 | ) -> Vec<LocatedImport> { |
189 | let current_crate = self.module_with_candidate.krate(); | 191 | let current_crate = self.module_with_candidate.krate(); |
190 | 192 | ||
@@ -223,7 +225,7 @@ impl ImportAssets { | |||
223 | fn applicable_defs( | 225 | fn applicable_defs( |
224 | &self, | 226 | &self, |
225 | db: &RootDatabase, | 227 | db: &RootDatabase, |
226 | prefixed: Option<hir::PrefixKind>, | 228 | prefixed: Option<PrefixKind>, |
227 | unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>, | 229 | unfiltered_defs: impl Iterator<Item = Either<ModuleDef, MacroDef>>, |
228 | ) -> FxHashSet<LocatedImport> { | 230 | ) -> FxHashSet<LocatedImport> { |
229 | let current_crate = self.module_with_candidate.krate(); | 231 | let current_crate = self.module_with_candidate.krate(); |
@@ -266,10 +268,10 @@ fn path_applicable_imports( | |||
266 | let (assoc_original, candidate) = match def { | 268 | let (assoc_original, candidate) = match def { |
267 | Either::Left(module_def) => match module_def.as_assoc_item(db) { | 269 | Either::Left(module_def) => match module_def.as_assoc_item(db) { |
268 | Some(assoc_item) => match assoc_item.container(db) { | 270 | Some(assoc_item) => match assoc_item.container(db) { |
269 | hir::AssocItemContainer::Trait(trait_) => { | 271 | AssocItemContainer::Trait(trait_) => { |
270 | (Some(module_def), ItemInNs::from(ModuleDef::from(trait_))) | 272 | (Some(module_def), ItemInNs::from(ModuleDef::from(trait_))) |
271 | } | 273 | } |
272 | hir::AssocItemContainer::Impl(impl_) => ( | 274 | AssocItemContainer::Impl(impl_) => ( |
273 | Some(module_def), | 275 | Some(module_def), |
274 | ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?)), | 276 | ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?)), |
275 | ), | 277 | ), |
@@ -296,6 +298,7 @@ fn path_applicable_imports( | |||
296 | }; | 298 | }; |
297 | 299 | ||
298 | // TODO kb need to remove turbofish from the qualifier, maybe use the segments instead? | 300 | // TODO kb need to remove turbofish from the qualifier, maybe use the segments instead? |
301 | // TODO kb sorting is changed now, return back? | ||
299 | let unresolved_qualifier_string = unresolved_qualifier.to_string(); | 302 | let unresolved_qualifier_string = unresolved_qualifier.to_string(); |
300 | let unresolved_first_segment_string = unresolved_first_segment.to_string(); | 303 | let unresolved_first_segment_string = unresolved_first_segment.to_string(); |
301 | 304 | ||
@@ -305,38 +308,35 @@ fn path_applicable_imports( | |||
305 | candidate_path_string.contains(&unresolved_qualifier_string) | 308 | candidate_path_string.contains(&unresolved_qualifier_string) |
306 | && candidate_path_string.contains(&unresolved_first_segment_string) | 309 | && candidate_path_string.contains(&unresolved_first_segment_string) |
307 | }) | 310 | }) |
308 | // TODO kb need to adjust the return type: I get the results rendered rather badly | ||
309 | .filter_map(|(candidate_path, (assoc_original, candidate))| { | 311 | .filter_map(|(candidate_path, (assoc_original, candidate))| { |
310 | if let Some(assoc_original) = assoc_original { | 312 | let found_segment_resolution = item_name(db, candidate) |
311 | if item_name(db, candidate)?.to_string() == unresolved_first_segment_string { | 313 | .map(|name| name.to_string() == unresolved_first_segment_string) |
312 | return Some(LocatedImport::new( | 314 | .unwrap_or(false); |
313 | candidate_path.clone(), | 315 | let (import_path, item_to_import) = if found_segment_resolution { |
314 | ItemInNs::from(assoc_original), | 316 | (candidate_path.clone(), candidate) |
315 | Some((candidate_path, candidate)), | 317 | } else { |
316 | )); | 318 | let matching_module = |
317 | } | 319 | module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; |
318 | } | 320 | let module_item = ItemInNs::from(ModuleDef::from(matching_module)); |
321 | (import_path_locator(module_item)?, module_item) | ||
322 | }; | ||
319 | 323 | ||
320 | let matching_module = | 324 | Some(match assoc_original { |
321 | module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; | 325 | Some(assoc_original) => LocatedImport::new( |
322 | let item = ItemInNs::from(ModuleDef::from(matching_module)); | 326 | import_path.clone(), |
323 | Some(LocatedImport::new( | 327 | item_to_import, |
324 | import_path_locator(item)?, | 328 | Some((import_path, ItemInNs::from(assoc_original))), |
325 | item, | 329 | ), |
326 | Some((candidate_path, candidate)), | 330 | None => LocatedImport::new( |
327 | )) | 331 | import_path, |
332 | item_to_import, | ||
333 | if found_segment_resolution { None } else { Some((candidate_path, candidate)) }, | ||
334 | ), | ||
335 | }) | ||
328 | }) | 336 | }) |
329 | .collect() | 337 | .collect() |
330 | } | 338 | } |
331 | 339 | ||
332 | fn item_name(db: &RootDatabase, item: ItemInNs) -> Option<Name> { | ||
333 | match item { | ||
334 | ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).name(db), | ||
335 | ItemInNs::Values(module_def_id) => ModuleDef::from(module_def_id).name(db), | ||
336 | ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db), | ||
337 | } | ||
338 | } | ||
339 | |||
340 | fn item_module(db: &RootDatabase, item: ItemInNs) -> Option<Module> { | 340 | fn item_module(db: &RootDatabase, item: ItemInNs) -> Option<Module> { |
341 | match item { | 341 | match item { |
342 | ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).module(db), | 342 | ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).module(db), |
@@ -404,10 +404,20 @@ fn trait_applicable_items( | |||
404 | } | 404 | } |
405 | 405 | ||
406 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); | 406 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); |
407 | let item_path = import_path_locator(item)?; | ||
408 | |||
409 | let assoc_item = assoc_to_item(assoc); | ||
410 | let assoc_item_path = match assoc.container(db) { | ||
411 | AssocItemContainer::Trait(_) => item_path.clone(), | ||
412 | AssocItemContainer::Impl(impl_) => import_path_locator(ItemInNs::from( | ||
413 | ModuleDef::from(impl_.target_ty(db).as_adt()?), | ||
414 | ))?, | ||
415 | }; | ||
416 | |||
407 | located_imports.insert(LocatedImport::new( | 417 | located_imports.insert(LocatedImport::new( |
408 | import_path_locator(item)?, | 418 | item_path, |
409 | item, | 419 | item, |
410 | None, | 420 | Some((assoc_item_path, assoc_item)), |
411 | )); | 421 | )); |
412 | } | 422 | } |
413 | None::<()> | 423 | None::<()> |
@@ -423,10 +433,20 @@ fn trait_applicable_items( | |||
423 | let assoc = function.as_assoc_item(db)?; | 433 | let assoc = function.as_assoc_item(db)?; |
424 | if required_assoc_items.contains(&assoc) { | 434 | if required_assoc_items.contains(&assoc) { |
425 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); | 435 | let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); |
436 | let item_path = import_path_locator(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_) => import_path_locator(ItemInNs::from( | ||
442 | ModuleDef::from(impl_.target_ty(db).as_adt()?), | ||
443 | ))?, | ||
444 | }; | ||
445 | |||
426 | located_imports.insert(LocatedImport::new( | 446 | located_imports.insert(LocatedImport::new( |
427 | import_path_locator(item)?, | 447 | item_path, |
428 | item, | 448 | item, |
429 | None, | 449 | Some((assoc_item_path, assoc_item)), |
430 | )); | 450 | )); |
431 | } | 451 | } |
432 | None::<()> | 452 | None::<()> |
@@ -437,11 +457,19 @@ fn trait_applicable_items( | |||
437 | located_imports | 457 | located_imports |
438 | } | 458 | } |
439 | 459 | ||
460 | fn assoc_to_item(assoc: AssocItem) -> ItemInNs { | ||
461 | match assoc { | ||
462 | AssocItem::Function(f) => ItemInNs::from(ModuleDef::from(f)), | ||
463 | AssocItem::Const(c) => ItemInNs::from(ModuleDef::from(c)), | ||
464 | AssocItem::TypeAlias(t) => ItemInNs::from(ModuleDef::from(t)), | ||
465 | } | ||
466 | } | ||
467 | |||
440 | fn get_mod_path( | 468 | fn get_mod_path( |
441 | db: &RootDatabase, | 469 | db: &RootDatabase, |
442 | item_to_search: ItemInNs, | 470 | item_to_search: ItemInNs, |
443 | module_with_candidate: &Module, | 471 | module_with_candidate: &Module, |
444 | prefixed: Option<hir::PrefixKind>, | 472 | prefixed: Option<PrefixKind>, |
445 | ) -> Option<ModPath> { | 473 | ) -> Option<ModPath> { |
446 | if let Some(prefix_kind) = prefixed { | 474 | if let Some(prefix_kind) = prefixed { |
447 | module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind) | 475 | module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind) |
@@ -509,7 +537,7 @@ fn path_import_candidate( | |||
509 | return None; | 537 | return None; |
510 | } | 538 | } |
511 | } | 539 | } |
512 | Some(hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path))) => { | 540 | Some(PathResolution::Def(ModuleDef::Adt(assoc_item_path))) => { |
513 | ImportCandidate::TraitAssocItem(TraitImportCandidate { | 541 | ImportCandidate::TraitAssocItem(TraitImportCandidate { |
514 | receiver_ty: assoc_item_path.ty(sema.db), | 542 | receiver_ty: assoc_item_path.ty(sema.db), |
515 | name, | 543 | name, |