diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs index f46054e8cc..b94b500040 100644 --- a/crates/hir-def/src/find_path.rs +++ b/crates/hir-def/src/find_path.rs @@ -1,6 +1,6 @@ //! An algorithm to find a path to refer to a certain item. -use std::iter; +use std::{cmp::Ordering, iter}; use hir_expand::name::{known, AsName, Name}; use rustc_hash::FxHashSet; @@ -20,10 +20,10 @@ pub fn find_path( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, - prefer_core: bool, + prefer_no_std: bool, ) -> Option { let _p = profile::span("find_path"); - find_path_inner(db, item, from, None, prefer_core) + find_path_inner(db, item, from, None, prefer_no_std) } pub fn find_path_prefixed( @@ -31,48 +31,14 @@ pub fn find_path_prefixed( item: ItemInNs, from: ModuleId, prefix_kind: PrefixKind, - prefer_core: bool, + prefer_no_std: bool, ) -> Option { let _p = profile::span("find_path_prefixed"); - find_path_inner(db, item, from, Some(prefix_kind), prefer_core) + find_path_inner(db, item, from, Some(prefix_kind), prefer_no_std) } const MAX_PATH_LEN: usize = 15; -trait ModPathExt { - fn starts_with_std(&self) -> bool; - fn can_start_with_std(&self) -> bool; -} - -impl ModPathExt for ModPath { - fn starts_with_std(&self) -> bool { - self.segments().first() == Some(&known::std) - } - - // Can we replace the first segment with `std::` and still get a valid, identical path? - fn can_start_with_std(&self) -> bool { - let first_segment = self.segments().first(); - first_segment == Some(&known::alloc) || first_segment == Some(&known::core) - } -} - -fn check_self_super(def_map: &DefMap, item: ItemInNs, from: ModuleId) -> Option { - if item == ItemInNs::Types(from.into()) { - // - if the item is the module we're in, use `self` - Some(ModPath::from_segments(PathKind::Super(0), None)) - } else if let Some(parent_id) = def_map[from.local_id].parent { - // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) - let parent_id = def_map.module_id(parent_id); - if item == ItemInNs::Types(ModuleDefId::ModuleId(parent_id)) { - Some(ModPath::from_segments(PathKind::Super(1), None)) - } else { - None - } - } else { - None - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum PrefixKind { /// Causes paths to always start with either `self`, `super`, `crate` or a crate-name. @@ -100,117 +66,60 @@ impl PrefixKind { self == &PrefixKind::ByCrate } } + /// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId fn find_path_inner( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, prefixed: Option, - prefer_core: bool, + prefer_no_std: bool, ) -> Option { - // FIXME: Do fast path for std/core libs? - - let mut visited_modules = FxHashSet::default(); - let def_map = from.def_map(db); - find_path_inner_( - db, - &def_map, - from, - item, - MAX_PATH_LEN, - prefixed, - &mut visited_modules, - prefer_core, - ) -} - -fn find_path_inner_( - db: &dyn DefDatabase, - def_map: &DefMap, - from: ModuleId, - item: ItemInNs, - max_len: usize, - mut prefixed: Option, - visited_modules: &mut FxHashSet, - prefer_core: bool, -) -> Option { - if max_len == 0 { - return None; + // - if the item is a builtin, it's in scope + if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item { + return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name()))); } - // Base cases: + let def_map = from.def_map(db); + let crate_root = def_map.crate_root(db); + // - if the item is a module, jump straight to module search + if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item { + let mut visited_modules = FxHashSet::default(); + return find_path_for_module( + db, + &def_map, + &mut visited_modules, + crate_root, + from, + module_id, + MAX_PATH_LEN, + prefixed, + prefer_no_std || db.crate_supports_no_std(crate_root.krate), + ); + } // - if the item is already in scope, return the name under which it is - let scope_name = def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { - def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone()) - }); + let scope_name = find_in_scope(db, &def_map, from, item); if prefixed.is_none() { if let Some(scope_name) = scope_name { return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name))); } } - // - if the item is a builtin, it's in scope - if let ItemInNs::Types(ModuleDefId::BuiltinType(builtin)) = item { - return Some(ModPath::from_segments(PathKind::Plain, Some(builtin.as_name()))); - } - - // - if the item is the crate root, return `crate` - let crate_root = def_map.crate_root(db); - if item == ItemInNs::Types(ModuleDefId::ModuleId(crate_root)) { - return Some(ModPath::from_segments(PathKind::Crate, None)); - } - - if prefixed.filter(PrefixKind::is_absolute).is_none() { - if let modpath @ Some(_) = check_self_super(&def_map, item, from) { - return modpath; - } - } - - // - if the item is the crate root of a dependency crate, return the name from the extern prelude - let root_def_map = crate_root.def_map(db); - if let ItemInNs::Types(ModuleDefId::ModuleId(item)) = item { - for (name, &def_id) in root_def_map.extern_prelude() { - if item == def_id { - let name = scope_name.unwrap_or_else(|| name.clone()); - - let name_already_occupied_in_type_ns = def_map - .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { - def_map[local_id] - .scope - .type_(&name) - .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id)) - }) - .is_some(); - let kind = if name_already_occupied_in_type_ns { - cov_mark::hit!(ambiguous_crate_start); - PathKind::Abs - } else { - PathKind::Plain - }; - return Some(ModPath::from_segments(kind, Some(name))); - } - } - } - // - if the item is in the prelude, return the name from there - if let Some(prelude_module) = root_def_map.prelude() { - // Preludes in block DefMaps are ignored, only the crate DefMap is searched - let prelude_def_map = prelude_module.def_map(db); - let prelude_scope = &prelude_def_map[prelude_module.local_id].scope; - if let Some((name, vis)) = prelude_scope.name_of(item) { - if vis.is_visible_from(db, from) { - return Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))); - } - } + if let Some(value) = find_in_prelude(db, &crate_root.def_map(db), item, from) { + return value; } - // Recursive case: - // - if the item is an enum variant, refer to it via the enum if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() { - if let Some(mut path) = - find_path(db, ItemInNs::Types(variant.parent.into()), from, prefer_core) - { + // - if the item is an enum variant, refer to it via the enum + if let Some(mut path) = find_path_inner( + db, + ItemInNs::Types(variant.parent.into()), + from, + prefixed, + prefer_no_std, + ) { let data = db.enum_data(variant.parent); path.push_segment(data.variants[variant.local_id].name.clone()); return Some(path); @@ -220,29 +129,184 @@ fn find_path_inner_( // variant somewhere } - // - otherwise, look for modules containing (reexporting) it and import it from one of those - let prefer_no_std = prefer_core || db.crate_supports_no_std(crate_root.krate); - let mut best_path = None; - let mut best_path_len = max_len; + let mut visited_modules = FxHashSet::default(); + calculate_best_path( + db, + &def_map, + &mut visited_modules, + crate_root, + MAX_PATH_LEN, + item, + from, + prefixed, + prefer_no_std || db.crate_supports_no_std(crate_root.krate), + scope_name, + ) +} + +fn find_path_for_module( + db: &dyn DefDatabase, + def_map: &DefMap, + visited_modules: &mut FxHashSet, + crate_root: ModuleId, + from: ModuleId, + module_id: ModuleId, + max_len: usize, + prefixed: Option, + prefer_no_std: bool, +) -> Option { + if max_len == 0 { + return None; + } + + // Base cases: + // - if the item is already in scope, return the name under which it is + let scope_name = find_in_scope(db, def_map, from, ItemInNs::Types(module_id.into())); + if prefixed.is_none() { + if let Some(scope_name) = scope_name { + return Some(ModPath::from_segments(PathKind::Plain, Some(scope_name))); + } + } + + // - if the item is the crate root, return `crate` + if module_id == crate_root { + return Some(ModPath::from_segments(PathKind::Crate, None)); + } + + // - if relative paths are fine, check if we are searching for a parent + if prefixed.filter(PrefixKind::is_absolute).is_none() { + if let modpath @ Some(_) = find_self_super(&def_map, module_id, from) { + return modpath; + } + } + + // - if the item is the crate root of a dependency crate, return the name from the extern prelude + let root_def_map = crate_root.def_map(db); + for (name, &def_id) in root_def_map.extern_prelude() { + if module_id == def_id { + let name = scope_name.unwrap_or_else(|| name.clone()); + + let name_already_occupied_in_type_ns = def_map + .with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { + def_map[local_id] + .scope + .type_(&name) + .filter(|&(id, _)| id != ModuleDefId::ModuleId(def_id)) + }) + .is_some(); + let kind = if name_already_occupied_in_type_ns { + cov_mark::hit!(ambiguous_crate_start); + PathKind::Abs + } else { + PathKind::Plain + }; + return Some(ModPath::from_segments(kind, Some(name))); + } + } + + if let Some(value) = find_in_prelude(db, &root_def_map, ItemInNs::Types(module_id.into()), from) + { + return value; + } + calculate_best_path( + db, + def_map, + visited_modules, + crate_root, + max_len, + ItemInNs::Types(module_id.into()), + from, + prefixed, + prefer_no_std, + scope_name, + ) +} + +fn find_in_scope( + db: &dyn DefDatabase, + def_map: &DefMap, + from: ModuleId, + item: ItemInNs, +) -> Option { + def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| { + def_map[local_id].scope.name_of(item).map(|(name, _)| name.clone()) + }) +} + +fn find_in_prelude( + db: &dyn DefDatabase, + root_def_map: &DefMap, + item: ItemInNs, + from: ModuleId, +) -> Option> { + if let Some(prelude_module) = root_def_map.prelude() { + // Preludes in block DefMaps are ignored, only the crate DefMap is searched + let prelude_def_map = prelude_module.def_map(db); + let prelude_scope = &prelude_def_map[prelude_module.local_id].scope; + if let Some((name, vis)) = prelude_scope.name_of(item) { + if vis.is_visible_from(db, from) { + return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone())))); + } + } + } + None +} + +fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option { + if item == from { + // - if the item is the module we're in, use `self` + Some(ModPath::from_segments(PathKind::Super(0), None)) + } else if let Some(parent_id) = def_map[from.local_id].parent { + // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) + let parent_id = def_map.module_id(parent_id); + if item == parent_id { + Some(ModPath::from_segments(PathKind::Super(1), None)) + } else { + None + } + } else { + None + } +} + +fn calculate_best_path( + db: &dyn DefDatabase, + def_map: &DefMap, + visited_modules: &mut FxHashSet, + crate_root: ModuleId, + max_len: usize, + item: ItemInNs, + from: ModuleId, + mut prefixed: Option, + prefer_no_std: bool, + scope_name: Option, +) -> Option { + if max_len <= 1 { + return None; + } + let mut best_path = None; + // Recursive case: + // - otherwise, look for modules containing (reexporting) it and import it from one of those if item.krate(db) == Some(from.krate) { + let mut best_path_len = max_len; // Item was defined in the same crate that wants to import it. It cannot be found in any // dependency in this case. - // FIXME: this should have a fast path that doesn't look through the prelude again? for (module_id, name) in find_local_import_locations(db, item, from) { if !visited_modules.insert(module_id) { cov_mark::hit!(recursive_imports); continue; } - if let Some(mut path) = find_path_inner_( + if let Some(mut path) = find_path_for_module( db, def_map, + visited_modules, + crate_root, from, - ItemInNs::Types(ModuleDefId::ModuleId(module_id)), + module_id, best_path_len - 1, prefixed, - visited_modules, - prefer_core, + prefer_no_std, ) { path.push_segment(name); @@ -265,15 +329,16 @@ fn find_path_inner_( import_map.import_info_for(item).and_then(|info| { // Determine best path for containing module and append last segment from `info`. // FIXME: we should guide this to look up the path locally, or from the same crate again? - let mut path = find_path_inner_( + let mut path = find_path_for_module( db, def_map, - from, - ItemInNs::Types(ModuleDefId::ModuleId(info.container)), - best_path_len - 1, - prefixed, visited_modules, - prefer_core, + from, + crate_root, + info.container, + max_len - 1, + prefixed, + prefer_no_std, )?; cov_mark::hit!(partially_imported); path.push_segment(info.path.segments.last()?.clone()); @@ -289,16 +354,12 @@ fn find_path_inner_( best_path = Some(new_path); } } - - // If the item is declared inside a block expression, don't use a prefix, as we don't handle - // that correctly (FIXME). - if let Some(item_module) = item.as_module_def_id().and_then(|did| did.module(db)) { - if item_module.def_map(db).block_id().is_some() && prefixed.is_some() { + if let Some(module) = item.module(db) { + if module.def_map(db).block_id().is_some() && prefixed.is_some() { cov_mark::hit!(prefixed_in_block_expression); prefixed = Some(PrefixKind::Plain); } } - match prefixed.map(PrefixKind::prefix) { Some(prefix) => best_path.or_else(|| { scope_name.map(|scope_name| ModPath::from_segments(prefix, Some(scope_name))) @@ -308,29 +369,48 @@ fn find_path_inner_( } fn select_best_path(old_path: ModPath, new_path: ModPath, prefer_no_std: bool) -> ModPath { - if old_path.starts_with_std() && new_path.can_start_with_std() { - if prefer_no_std { - cov_mark::hit!(prefer_no_std_paths); - new_path - } else { - cov_mark::hit!(prefer_std_paths); - old_path + const STD_CRATES: [Name; 3] = [known::std, known::core, known::alloc]; + match (old_path.segments().first(), new_path.segments().first()) { + (Some(old), Some(new)) if STD_CRATES.contains(old) && STD_CRATES.contains(new) => { + let rank = match prefer_no_std { + false => |name: &Name| match name { + name if name == &known::core => 0, + name if name == &known::alloc => 0, + name if name == &known::std => 1, + _ => unreachable!(), + }, + true => |name: &Name| match name { + name if name == &known::core => 2, + name if name == &known::alloc => 1, + name if name == &known::std => 0, + _ => unreachable!(), + }, + }; + let nrank = rank(new); + let orank = rank(old); + match nrank.cmp(&orank) { + Ordering::Less => old_path, + Ordering::Equal => { + if new_path.len() < old_path.len() { + new_path + } else { + old_path + } + } + Ordering::Greater => new_path, + } } - } else if new_path.starts_with_std() && old_path.can_start_with_std() { - if prefer_no_std { - cov_mark::hit!(prefer_no_std_paths); - old_path - } else { - cov_mark::hit!(prefer_std_paths); - new_path + _ => { + if new_path.len() < old_path.len() { + new_path + } else { + old_path + } } - } else if new_path.len() < old_path.len() { - new_path - } else { - old_path } } +// FIXME: Remove allocations /// Finds locations in `from.krate` from which `item` can be imported by `from`. fn find_local_import_locations( db: &dyn DefDatabase, @@ -490,8 +570,8 @@ $0 "#, "E::A", "E::A", - "E::A", - "E::A", + "crate::E::A", + "self::E::A", ); } @@ -810,7 +890,6 @@ pub use super::foo; #[test] fn prefer_std_paths_over_alloc() { - cov_mark::check!(prefer_std_paths); check_found_path( r#" //- /main.rs crate:main deps:alloc,std @@ -835,7 +914,6 @@ pub mod sync { #[test] fn prefer_core_paths_over_std() { - cov_mark::check!(prefer_no_std_paths); check_found_path( r#" //- /main.rs crate:main deps:core,std diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs index a11a92204c..a40656fd6a 100644 --- a/crates/hir-def/src/item_scope.rs +++ b/crates/hir-def/src/item_scope.rs @@ -457,8 +457,15 @@ impl ItemInNs { /// Returns the crate defining this item (or `None` if `self` is built-in). pub fn krate(&self, db: &dyn DefDatabase) -> Option { match self { - ItemInNs::Types(did) | ItemInNs::Values(did) => did.module(db).map(|m| m.krate), + ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db).map(|m| m.krate), ItemInNs::Macros(id) => Some(id.module(db).krate), } } + + pub fn module(&self, db: &dyn DefDatabase) -> Option { + match self { + ItemInNs::Types(id) | ItemInNs::Values(id) => id.module(db), + ItemInNs::Macros(id) => Some(id.module(db)), + } + } } diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 7dd891c86e..b5974a0cfc 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -585,9 +585,9 @@ impl Module { self, db: &dyn DefDatabase, item: impl Into, - prefer_core: bool, + prefer_no_std: bool, ) -> Option { - hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_core) + hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_no_std) } /// Finds a path that can be used to refer to the given item from within @@ -597,14 +597,14 @@ impl Module { db: &dyn DefDatabase, item: impl Into, prefix_kind: PrefixKind, - prefer_core: bool, + prefer_no_std: bool, ) -> Option { hir_def::find_path::find_path_prefixed( db, item.into().into(), self.into(), prefix_kind, - prefer_core, + prefer_no_std, ) } } diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs index fe2dfca6d5..60d1588a44 100644 --- a/crates/ide-assists/src/assist_config.rs +++ b/crates/ide-assists/src/assist_config.rs @@ -13,5 +13,5 @@ pub struct AssistConfig { pub snippet_cap: Option, pub allowed: Option>, pub insert_use: InsertUseConfig, - pub prefer_core: bool, + pub prefer_no_std: bool, } diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs index d4e21b778c..73f4db4e5f 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -87,7 +87,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .into_iter() .filter_map(|variant| { Some(( - build_pat(ctx.db(), module, variant, ctx.config.prefer_core)?, + build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std)?, variant.should_be_hidden(ctx.db(), module.krate()), )) }) @@ -133,7 +133,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) .iter() .any(|variant| variant.should_be_hidden(ctx.db(), module.krate())); let patterns = variants.into_iter().filter_map(|variant| { - build_pat(ctx.db(), module, variant, ctx.config.prefer_core) + build_pat(ctx.db(), module, variant, ctx.config.prefer_no_std) }); (ast::Pat::from(make::tuple_pat(patterns)), is_hidden) @@ -354,12 +354,12 @@ fn build_pat( db: &RootDatabase, module: hir::Module, var: ExtendedVariant, - prefer_core: bool, + prefer_no_std: bool, ) -> Option { match var { ExtendedVariant::Variant(var) => { let path = - mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_core)?); + mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_no_std)?); // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though let pat: ast::Pat = match var.source(db)?.value.kind() { diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs index 88a6b8558c..e257218ba9 100644 --- a/crates/ide-assists/src/handlers/auto_import.rs +++ b/crates/ide-assists/src/handlers/auto_import.rs @@ -92,7 +92,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< let mut proposed_imports = import_assets.search_for_imports( &ctx.sema, ctx.config.insert_use.prefix_kind, - ctx.config.prefer_core, + ctx.config.prefer_no_std, ); if proposed_imports.is_empty() { return None; diff --git a/crates/ide-assists/src/handlers/convert_into_to_from.rs b/crates/ide-assists/src/handlers/convert_into_to_from.rs index e0c0e9a484..95d11abe8b 100644 --- a/crates/ide-assists/src/handlers/convert_into_to_from.rs +++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs @@ -50,7 +50,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - _ => return None, }; - mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def, ctx.config.prefer_core)?) + mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def, ctx.config.prefer_no_std)?) }; let dest_type = match &ast_trait { diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs index 749d94d5a9..d6c8ea785f 100644 --- a/crates/ide-assists/src/handlers/extract_function.rs +++ b/crates/ide-assists/src/handlers/extract_function.rs @@ -152,7 +152,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op ctx.sema.db, ModuleDef::from(control_flow_enum), ctx.config.insert_use.prefix_kind, - ctx.config.prefer_core, + ctx.config.prefer_no_std, ); if let Some(mod_path) = mod_path { diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs index 431f7b3c0f..8d5cab283d 100644 --- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs @@ -409,7 +409,7 @@ fn process_references( ctx.sema.db, *enum_module_def, ctx.config.insert_use.prefix_kind, - ctx.config.prefer_core, + ctx.config.prefer_no_std, ); if let Some(mut mod_path) = mod_path { mod_path.pop_segment(); diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs index cf4ed84281..8f4405a8c8 100644 --- a/crates/ide-assists/src/handlers/generate_deref.rs +++ b/crates/ide-assists/src/handlers/generate_deref.rs @@ -59,7 +59,7 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let module = ctx.sema.to_def(&strukt)?.module(ctx.db()); let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?; let trait_path = - module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_core)?; + module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?; let field_type = field.ty()?; let field_name = field.name()?; @@ -100,7 +100,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<() let module = ctx.sema.to_def(&strukt)?.module(ctx.db()); let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?; let trait_path = - module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_core)?; + module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_no_std)?; let field_type = field.ty()?; let target = field.syntax().text_range(); diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index ceb7dac0fe..9cda74d9e0 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -63,7 +63,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let type_path = current_module.find_use_path( ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, - ctx.config.prefer_core, + ctx.config.prefer_no_std, )?; let expr = use_trivial_constructor( diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs index cb81ebd228..e57d1d065d 100644 --- a/crates/ide-assists/src/handlers/qualify_method_call.rs +++ b/crates/ide-assists/src/handlers/qualify_method_call.rs @@ -47,7 +47,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) -> let receiver_path = current_module.find_use_path( ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, - ctx.config.prefer_core, + ctx.config.prefer_no_std, )?; let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call); diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs index 232cd39e8b..4b2af550bc 100644 --- a/crates/ide-assists/src/handlers/qualify_path.rs +++ b/crates/ide-assists/src/handlers/qualify_path.rs @@ -38,7 +38,7 @@ use crate::{ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let (import_assets, syntax_under_caret) = find_importable_node(ctx)?; let mut proposed_imports = - import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_core); + import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_no_std); if proposed_imports.is_empty() { return None; } 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 04a1366327..9fd5e1886d 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 @@ -85,7 +85,7 @@ pub(crate) fn replace_derive_with_manual_impl( }) .flat_map(|trait_| { current_module - .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_core) + .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_no_std) .as_ref() .map(mod_path_to_ast) .zip(Some(trait_)) diff --git a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs index 533e1670a0..dbbc56958f 100644 --- a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs @@ -67,7 +67,7 @@ pub(crate) fn replace_qualified_name_with_use( ctx.sema.db, module, ctx.config.insert_use.prefix_kind, - ctx.config.prefer_core, + ctx.config.prefer_no_std, ) }) .flatten(); diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs index 4e589dc86a..258144bae3 100644 --- a/crates/ide-assists/src/tests.rs +++ b/crates/ide-assists/src/tests.rs @@ -29,7 +29,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { group: true, skip_glob_imports: true, }, - prefer_core: false, + prefer_no_std: false, }; pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs index 89a971e544..97b90c62dd 100644 --- a/crates/ide-completion/src/completions.rs +++ b/crates/ide-completion/src/completions.rs @@ -551,9 +551,11 @@ fn enum_variants_with_paths( } for variant in variants { - if let Some(path) = - ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant), ctx.config.prefer_core) - { + if let Some(path) = ctx.module.find_use_path( + ctx.db, + hir::ModuleDef::from(variant), + ctx.config.prefer_no_std, + ) { // Variants with trivial paths are already added by the existing completion logic, // so we should avoid adding these twice if path.segments().len() > 1 { diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs index 1ccf33a96b..3192b21cfb 100644 --- a/crates/ide-completion/src/completions/expr.rs +++ b/crates/ide-completion/src/completions/expr.rs @@ -168,7 +168,7 @@ pub(crate) fn complete_expr_path( .find_use_path( ctx.db, hir::ModuleDef::from(strukt), - ctx.config.prefer_core, + ctx.config.prefer_no_std, ) .filter(|it| it.len() > 1); @@ -187,7 +187,11 @@ pub(crate) fn complete_expr_path( hir::Adt::Union(un) => { let path = ctx .module - .find_use_path(ctx.db, hir::ModuleDef::from(un), ctx.config.prefer_core) + .find_use_path( + ctx.db, + hir::ModuleDef::from(un), + ctx.config.prefer_no_std, + ) .filter(|it| it.len() > 1); acc.add_union_literal(ctx, un, path, None); diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs index 528959943b..364969af9c 100644 --- a/crates/ide-completion/src/completions/flyimport.rs +++ b/crates/ide-completion/src/completions/flyimport.rs @@ -265,7 +265,7 @@ fn import_on_the_fly( .search_for_imports( &ctx.sema, ctx.config.insert_use.prefix_kind, - ctx.config.prefer_core, + ctx.config.prefer_no_std, ) .into_iter() .filter(ns_filter) @@ -313,7 +313,7 @@ fn import_on_the_fly_pat_( .search_for_imports( &ctx.sema, ctx.config.insert_use.prefix_kind, - ctx.config.prefer_core, + ctx.config.prefer_no_std, ) .into_iter() .filter(ns_filter) @@ -352,7 +352,7 @@ fn import_on_the_fly_method( let user_input_lowercased = potential_import_name.to_lowercase(); import_assets - .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_core) + .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_no_std) .into_iter() .filter(|import| { !ctx.is_item_hidden(&import.item_to_import) diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs index 54ebce1eb7..a0f5e81b4f 100644 --- a/crates/ide-completion/src/config.rs +++ b/crates/ide-completion/src/config.rs @@ -17,7 +17,7 @@ pub struct CompletionConfig { pub callable: Option, pub snippet_cap: Option, pub insert_use: InsertUseConfig, - pub prefer_core: bool, + pub prefer_no_std: bool, pub snippets: Vec, } diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs index 7cefb6bb4a..8d21f4fce0 100644 --- a/crates/ide-completion/src/lib.rs +++ b/crates/ide-completion/src/lib.rs @@ -238,7 +238,7 @@ pub fn resolve_completion_edits( db, candidate, config.insert_use.prefix_kind, - config.prefer_core, + config.prefer_no_std, ) }) .find(|mod_path| mod_path.to_string() == full_import_path); diff --git a/crates/ide-completion/src/snippet.rs b/crates/ide-completion/src/snippet.rs index 2dc62bbdc6..f3b8eae4fe 100644 --- a/crates/ide-completion/src/snippet.rs +++ b/crates/ide-completion/src/snippet.rs @@ -178,7 +178,7 @@ fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option 1).then(|| LocatedImport::new(path.clone(), item, item, None))) }; diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs index d24c914856..9e2beb9ee3 100644 --- a/crates/ide-completion/src/tests.rs +++ b/crates/ide-completion/src/tests.rs @@ -66,7 +66,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { enable_private_editable: false, callable: Some(CallableSnippets::FillArguments), snippet_cap: SnippetCap::new(true), - prefer_core: false, + prefer_no_std: false, insert_use: InsertUseConfig { granularity: ImportGranularity::Crate, prefix_kind: PrefixKind::Plain, diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs index 53bc516109..40a6a3e897 100644 --- a/crates/ide-db/src/imports/import_assets.rs +++ b/crates/ide-db/src/imports/import_assets.rs @@ -212,20 +212,20 @@ impl ImportAssets { &self, sema: &Semantics<'_, RootDatabase>, prefix_kind: PrefixKind, - prefer_core: bool, + prefer_no_std: bool, ) -> Vec { let _p = profile::span("import_assets::search_for_imports"); - self.search_for(sema, Some(prefix_kind), prefer_core) + self.search_for(sema, Some(prefix_kind), prefer_no_std) } /// This may return non-absolute paths if a part of the returned path is already imported into scope. pub fn search_for_relative_paths( &self, sema: &Semantics<'_, RootDatabase>, - prefer_core: bool, + prefer_no_std: bool, ) -> Vec { let _p = profile::span("import_assets::search_for_relative_paths"); - self.search_for(sema, None, prefer_core) + self.search_for(sema, None, prefer_no_std) } pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) { @@ -244,7 +244,7 @@ impl ImportAssets { &self, sema: &Semantics<'_, RootDatabase>, prefixed: Option, - prefer_core: bool, + prefer_no_std: bool, ) -> Vec { let _p = profile::span("import_assets::search_for"); @@ -255,7 +255,7 @@ impl ImportAssets { item_for_path_search(sema.db, item)?, &self.module_with_candidate, prefixed, - prefer_core, + prefer_no_std, ) }; @@ -568,12 +568,12 @@ fn get_mod_path( item_to_search: ItemInNs, module_with_candidate: &Module, prefixed: Option, - prefer_core: bool, + prefer_no_std: bool, ) -> Option { if let Some(prefix_kind) = prefixed { - module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind, prefer_core) + module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind, prefer_no_std) } else { - module_with_candidate.find_use_path(db, item_to_search, prefer_core) + module_with_candidate.find_use_path(db, item_to_search, prefer_no_std) } } diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 06073ca1b2..3034295196 100644 --- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -137,7 +137,7 @@ pub(crate) fn json_in_items( sema.db, it, config.insert_use.prefix_kind, - config.prefer_core, + config.prefer_no_std, ) { insert_use( &scope, @@ -153,7 +153,7 @@ pub(crate) fn json_in_items( sema.db, it, config.insert_use.prefix_kind, - config.prefer_core, + config.prefer_no_std, ) { insert_use( &scope, diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 5a81a55d82..7f140eb6a7 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -124,7 +124,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option ExprFillDefaultMode::Default, }, insert_use: self.insert_use_config(), - prefer_core: self.data.imports_prefer_core, + prefer_no_std: self.data.imports_prefer_no_std, } } @@ -1138,7 +1138,7 @@ impl Config { CallableCompletionDef::None => None, }, insert_use: self.insert_use_config(), - prefer_core: self.data.imports_prefer_core, + prefer_no_std: self.data.imports_prefer_no_std, snippet_cap: SnippetCap::new(try_or_def!( self.caps .text_document @@ -1166,7 +1166,7 @@ impl Config { snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")), allowed: None, insert_use: self.insert_use_config(), - prefer_core: self.data.imports_prefer_core, + prefer_no_std: self.data.imports_prefer_no_std, } } diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index 5dbb64d7df..96b1cb6b12 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -145,7 +145,7 @@ fn integrated_completion_benchmark() { skip_glob_imports: true, }, snippets: Vec::new(), - prefer_core: false, + prefer_no_std: false, }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; @@ -183,7 +183,7 @@ fn integrated_completion_benchmark() { skip_glob_imports: true, }, snippets: Vec::new(), - prefer_core: false, + prefer_no_std: false, }; let position = FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() }; diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 2b02c64b66..e596e08f2c 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -353,10 +353,10 @@ Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-i -- Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. -- -[[rust-analyzer.imports.prefer.core]]rust-analyzer.imports.prefer.core (default: `false`):: +[[rust-analyzer.imports.prefer.no.std]]rust-analyzer.imports.prefer.no.std (default: `false`):: + -- -Prefer to use imports of the core crate over the std crate. +Prefer to unconditionally use imports of the core and alloc crate, over the std crate. -- [[rust-analyzer.imports.prefix]]rust-analyzer.imports.prefix (default: `"plain"`):: + diff --git a/editors/code/package.json b/editors/code/package.json index cfba00d3ed..6aa74ce92a 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -798,8 +798,8 @@ "default": true, "type": "boolean" }, - "rust-analyzer.imports.prefer.core": { - "markdownDescription": "Prefer to use imports of the core crate over the std crate.", + "rust-analyzer.imports.prefer.no.std": { + "markdownDescription": "Prefer to unconditionally use imports of the core and alloc crate, over the std crate.", "default": false, "type": "boolean" },