From d386481fac65e988fa4d13c1bc8d4ddb2bc490c6 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 25 Feb 2021 01:53:59 +0200 Subject: Fix some tests --- crates/ide_completion/src/completions/flyimport.rs | 65 +++++++++++- crates/ide_completion/src/render.rs | 7 +- crates/ide_db/src/helpers.rs | 10 +- crates/ide_db/src/helpers/import_assets.rs | 110 +++++++++++++-------- 4 files changed, 143 insertions(+), 49 deletions(-) (limited to 'crates') 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) .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind) .into_iter() .map(|import| { - let proposed_def = match import.item_to_import() { + let proposed_def = match import.item_to_display() { hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()), hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()), hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()), @@ -809,7 +809,7 @@ fn main() { #[test] fn unresolved_assoc_item_container() { check_edit( - "Item", + "TEST_ASSOC", r#" mod foo { pub struct Item; @@ -820,7 +820,7 @@ mod foo { } fn main() { - Item::TEST_A$0; + Item::TEST_A$0 } "#, r#" @@ -844,7 +844,7 @@ fn main() { #[test] fn unresolved_assoc_item_container_with_path() { check_edit( - "Item", + "TEST_ASSOC", r#" mod foo { pub mod bar { @@ -857,7 +857,7 @@ mod foo { } fn main() { - bar::Item::TEST_A$0; + bar::Item::TEST_A$0 } "#, r#" @@ -876,6 +876,61 @@ mod foo { fn main() { bar::Item::TEST_ASSOC } +"#, + ); + } + + #[test] + fn unresolved_assoc_item_container_and_trait_with_path() { + check_edit( + "TEST_ASSOC", + r#" +mod foo { + pub mod bar { + pub trait SomeTrait { + const TEST_ASSOC: usize; + } + } + + pub mod baz { + use super::bar::SomeTrait; + + pub struct Item; + + impl SomeTrait for Item { + const TEST_ASSOC: usize = 3; + } + } +} + +fn main() { + baz::Item::TEST_A$0 +} +"#, + r#" +use foo::{bar::SomeTrait, baz}; + +mod foo { + pub mod bar { + pub trait SomeTrait { + const TEST_ASSOC: usize; + } + } + + pub mod baz { + use super::bar::SomeTrait; + + pub struct Item; + + impl SomeTrait for Item { + const TEST_ASSOC: usize = 3; + } + } +} + +fn main() { + baz::Item::TEST_ASSOC +} "#, ); } 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; use hir::{ AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, }; -use ide_db::{helpers::SnippetCap, RootDatabase, SymbolKind}; +use ide_db::{ + helpers::{item_name, SnippetCap}, + RootDatabase, SymbolKind, +}; use syntax::TextRange; use crate::{ @@ -56,7 +59,7 @@ pub(crate) fn render_resolution_with_import<'a>( ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(), ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(), ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(), - _ => import_edit.import.display_path().segments().last()?.to_string(), + _ => item_name(ctx.db(), import_edit.import.item_to_display())?.to_string(), }; Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| { 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 @@ pub mod insert_use; pub mod import_assets; -use hir::{Crate, Enum, Module, ScopeDef, Semantics, Trait}; +use hir::{Crate, Enum, ItemInNs, MacroDef, Module, ModuleDef, Name, ScopeDef, Semantics, Trait}; use syntax::ast::{self, make}; use crate::RootDatabase; +pub fn item_name(db: &RootDatabase, item: ItemInNs) -> Option { + match item { + ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).name(db), + ItemInNs::Values(module_def_id) => ModuleDef::from(module_def_id).name(db), + ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db), + } +} + /// Converts the mod path struct into its ast representation. pub fn mod_path_to_ast(path: &hir::ModPath) -> ast::Path { 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 @@ //! Look up accessible paths for items. use either::Either; use hir::{ - AsAssocItem, AssocItem, Crate, ItemInNs, MacroDef, ModPath, Module, ModuleDef, Name, - PrefixKind, Semantics, + AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module, + ModuleDef, PathResolution, PrefixKind, Semantics, Type, }; use rustc_hash::FxHashSet; use syntax::{ast, AstNode}; @@ -12,6 +12,8 @@ use crate::{ RootDatabase, }; +use super::item_name; + #[derive(Debug)] pub enum ImportCandidate { // A path, qualified (`std::collections::HashMap`) or not (`HashMap`). @@ -28,7 +30,7 @@ pub enum ImportCandidate { #[derive(Debug)] pub struct TraitImportCandidate { - pub receiver_ty: hir::Type, + pub receiver_ty: Type, pub name: NameToImport, } @@ -62,7 +64,7 @@ impl NameToImport { #[derive(Debug)] pub struct ImportAssets { import_candidate: ImportCandidate, - module_with_candidate: hir::Module, + module_with_candidate: Module, } impl ImportAssets { @@ -104,7 +106,7 @@ impl ImportAssets { pub fn for_fuzzy_method_call( module_with_method_call: Module, - receiver_ty: hir::Type, + receiver_ty: Type, fuzzy_method_name: String, ) -> Option { Some(Self { @@ -184,7 +186,7 @@ impl ImportAssets { fn search_for( &self, sema: &Semantics, - prefixed: Option, + prefixed: Option, ) -> Vec { let current_crate = self.module_with_candidate.krate(); @@ -223,7 +225,7 @@ impl ImportAssets { fn applicable_defs( &self, db: &RootDatabase, - prefixed: Option, + prefixed: Option, unfiltered_defs: impl Iterator>, ) -> FxHashSet { let current_crate = self.module_with_candidate.krate(); @@ -266,10 +268,10 @@ fn path_applicable_imports( let (assoc_original, candidate) = match def { Either::Left(module_def) => match module_def.as_assoc_item(db) { Some(assoc_item) => match assoc_item.container(db) { - hir::AssocItemContainer::Trait(trait_) => { + AssocItemContainer::Trait(trait_) => { (Some(module_def), ItemInNs::from(ModuleDef::from(trait_))) } - hir::AssocItemContainer::Impl(impl_) => ( + AssocItemContainer::Impl(impl_) => ( Some(module_def), ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?)), ), @@ -296,6 +298,7 @@ fn path_applicable_imports( }; // TODO kb need to remove turbofish from the qualifier, maybe use the segments instead? + // TODO kb sorting is changed now, return back? let unresolved_qualifier_string = unresolved_qualifier.to_string(); let unresolved_first_segment_string = unresolved_first_segment.to_string(); @@ -305,38 +308,35 @@ fn path_applicable_imports( candidate_path_string.contains(&unresolved_qualifier_string) && candidate_path_string.contains(&unresolved_first_segment_string) }) - // TODO kb need to adjust the return type: I get the results rendered rather badly .filter_map(|(candidate_path, (assoc_original, candidate))| { - if let Some(assoc_original) = assoc_original { - if item_name(db, candidate)?.to_string() == unresolved_first_segment_string { - return Some(LocatedImport::new( - candidate_path.clone(), - ItemInNs::from(assoc_original), - Some((candidate_path, candidate)), - )); - } - } + let found_segment_resolution = item_name(db, candidate) + .map(|name| name.to_string() == unresolved_first_segment_string) + .unwrap_or(false); + let (import_path, item_to_import) = if found_segment_resolution { + (candidate_path.clone(), candidate) + } else { + let matching_module = + module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; + let module_item = ItemInNs::from(ModuleDef::from(matching_module)); + (import_path_locator(module_item)?, module_item) + }; - let matching_module = - module_with_matching_name(db, &unresolved_first_segment_string, candidate)?; - let item = ItemInNs::from(ModuleDef::from(matching_module)); - Some(LocatedImport::new( - import_path_locator(item)?, - item, - Some((candidate_path, candidate)), - )) + Some(match assoc_original { + Some(assoc_original) => LocatedImport::new( + import_path.clone(), + item_to_import, + Some((import_path, ItemInNs::from(assoc_original))), + ), + None => LocatedImport::new( + import_path, + item_to_import, + if found_segment_resolution { None } else { Some((candidate_path, candidate)) }, + ), + }) }) .collect() } -fn item_name(db: &RootDatabase, item: ItemInNs) -> Option { - match item { - ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).name(db), - ItemInNs::Values(module_def_id) => ModuleDef::from(module_def_id).name(db), - ItemInNs::Macros(macro_def_id) => MacroDef::from(macro_def_id).name(db), - } -} - fn item_module(db: &RootDatabase, item: ItemInNs) -> Option { match item { ItemInNs::Types(module_def_id) => ModuleDef::from(module_def_id).module(db), @@ -404,10 +404,20 @@ fn trait_applicable_items( } let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); + let item_path = import_path_locator(item)?; + + let assoc_item = assoc_to_item(assoc); + let assoc_item_path = match assoc.container(db) { + AssocItemContainer::Trait(_) => item_path.clone(), + AssocItemContainer::Impl(impl_) => import_path_locator(ItemInNs::from( + ModuleDef::from(impl_.target_ty(db).as_adt()?), + ))?, + }; + located_imports.insert(LocatedImport::new( - import_path_locator(item)?, + item_path, item, - None, + Some((assoc_item_path, assoc_item)), )); } None::<()> @@ -423,10 +433,20 @@ fn trait_applicable_items( let assoc = function.as_assoc_item(db)?; if required_assoc_items.contains(&assoc) { let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); + let item_path = import_path_locator(item)?; + + let assoc_item = assoc_to_item(assoc); + let assoc_item_path = match assoc.container(db) { + AssocItemContainer::Trait(_) => item_path.clone(), + AssocItemContainer::Impl(impl_) => import_path_locator(ItemInNs::from( + ModuleDef::from(impl_.target_ty(db).as_adt()?), + ))?, + }; + located_imports.insert(LocatedImport::new( - import_path_locator(item)?, + item_path, item, - None, + Some((assoc_item_path, assoc_item)), )); } None::<()> @@ -437,11 +457,19 @@ fn trait_applicable_items( located_imports } +fn assoc_to_item(assoc: AssocItem) -> ItemInNs { + match assoc { + AssocItem::Function(f) => ItemInNs::from(ModuleDef::from(f)), + AssocItem::Const(c) => ItemInNs::from(ModuleDef::from(c)), + AssocItem::TypeAlias(t) => ItemInNs::from(ModuleDef::from(t)), + } +} + fn get_mod_path( db: &RootDatabase, item_to_search: ItemInNs, module_with_candidate: &Module, - prefixed: Option, + prefixed: Option, ) -> Option { if let Some(prefix_kind) = prefixed { module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind) @@ -509,7 +537,7 @@ fn path_import_candidate( return None; } } - Some(hir::PathResolution::Def(hir::ModuleDef::Adt(assoc_item_path))) => { + Some(PathResolution::Def(ModuleDef::Adt(assoc_item_path))) => { ImportCandidate::TraitAssocItem(TraitImportCandidate { receiver_ty: assoc_item_path.ty(sema.db), name, -- cgit v1.2.3