aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs65
-rw-r--r--crates/ide_completion/src/render.rs7
-rw-r--r--crates/ide_db/src/helpers.rs10
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs110
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#"
814mod foo { 814mod foo {
815 pub struct Item; 815 pub struct Item;
@@ -820,7 +820,7 @@ mod foo {
820} 820}
821 821
822fn main() { 822fn 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#"
849mod foo { 849mod foo {
850 pub mod bar { 850 pub mod bar {
@@ -857,7 +857,7 @@ mod foo {
857} 857}
858 858
859fn main() { 859fn 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#"
888mod 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
906fn main() {
907 baz::Item::TEST_A$0
908}
909"#,
910 r#"
911use foo::{bar::SomeTrait, baz};
912
913mod 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
931fn 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;
13use hir::{ 13use hir::{
14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, 14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
15}; 15};
16use ide_db::{helpers::SnippetCap, RootDatabase, SymbolKind}; 16use ide_db::{
17 helpers::{item_name, SnippetCap},
18 RootDatabase, SymbolKind,
19};
17use syntax::TextRange; 20use syntax::TextRange;
18 21
19use crate::{ 22use 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 @@
2pub mod insert_use; 2pub mod insert_use;
3pub mod import_assets; 3pub mod import_assets;
4 4
5use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; 5use hir::{Crate, Enum, ItemInNs, MacroDef, Module, ModuleDef, Name, ScopeDef, Semantics, Trait};
6use syntax::ast::{self, make}; 6use syntax::ast::{self, make};
7 7
8use crate::RootDatabase; 8use crate::RootDatabase;
9 9
10pub 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.
11pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { 19pub 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.
2use either::Either; 2use either::Either;
3use hir::{ 3use 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};
7use rustc_hash::FxHashSet; 7use rustc_hash::FxHashSet;
8use syntax::{ast, AstNode}; 8use syntax::{ast, AstNode};
@@ -12,6 +12,8 @@ use crate::{
12 RootDatabase, 12 RootDatabase,
13}; 13};
14 14
15use super::item_name;
16
15#[derive(Debug)] 17#[derive(Debug)]
16pub enum ImportCandidate { 18pub 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)]
30pub struct TraitImportCandidate { 32pub 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)]
63pub struct ImportAssets { 65pub 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
68impl ImportAssets { 70impl 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
332fn 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
340fn item_module(db: &RootDatabase, item: ItemInNs) -> Option<Module> { 340fn 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
460fn 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
440fn get_mod_path( 468fn 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,