diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs index 23573dc3388d..eda35eba45c9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_type_alias.rs @@ -1,6 +1,6 @@ use either::Either; use hir::HirDisplay; -use ide_db::syntax_helpers::node_ext::walk_ty; +use ide_db::syntax_helpers::{node_ext::walk_ty, suggest_name::NameGenerator}; use syntax::{ ast::{self, AstNode, HasGenericArgs, HasGenericParams, HasName, edit::IndentLevel}, syntax_editor, @@ -40,9 +40,10 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> ); let target = ty.syntax().text_range(); + let scope = ctx.sema.scope(ty.syntax())?; let resolved_ty = ctx.sema.resolve_type(&ty)?; let resolved_ty = if !resolved_ty.contains_unknown() { - let module = ctx.sema.scope(ty.syntax())?.module(); + let module = scope.module(); resolved_ty.display_source_code(ctx.db(), module.into(), false).ok()? } else { ty.to_string() @@ -57,6 +58,7 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> let make = editor.make(); let resolved_ty = make.ty(&resolved_ty); + let name = &NameGenerator::new_from_scope_non_locals(Some(scope)).suggest_name("Type"); let mut known_generics = match item.generic_param_list() { Some(it) => it.generic_params().collect(), @@ -75,15 +77,15 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) -> // Replace original type with the alias let ty_args = generic_params.as_ref().map(|it| it.to_generic_args().generic_args()); let new_ty = if let Some(ty_args) = ty_args { - make.generic_ty_path_segment(make.name_ref("Type"), ty_args) + make.generic_ty_path_segment(make.name_ref(name), ty_args) } else { - make.path_segment(make.name_ref("Type")) + make.path_segment(make.name_ref(name)) }; editor.replace(ty.syntax(), new_ty.syntax()); // Insert new alias let ty_alias = - make.ty_alias(None, "Type", generic_params, None, None, Some((resolved_ty, None))); + make.ty_alias(None, name, generic_params, None, None, Some((resolved_ty, None))); if let Some(cap) = ctx.config.snippet_cap && let Some(name) = ty_alias.name() @@ -447,4 +449,41 @@ fn main() { "#, ) } + + #[test] + fn duplicate_names() { + check_assist( + extract_type_alias, + r" +struct Type; +struct S { + field: $0u8$0, +} + ", + r#" +struct Type; +type $0Type1 = u8; + +struct S { + field: Type1, +} + "#, + ); + + check_assist( + extract_type_alias, + r" +struct S { + field: $0u8$0, +} + ", + r#" +type $0Type1 = u8; + +struct S { + field: Type1, +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 3a785fbe80a0..09e611532066 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -123,6 +123,20 @@ pub fn new_from_scope_locals(scope: Option>) -> Self { generator } + pub fn new_from_scope_non_locals(scope: Option>) -> Self { + let mut generator = Self::default(); + if let Some(scope) = scope { + scope.process_all_names(&mut |name, scope| { + if let hir::ScopeDef::Local(_) = scope { + return; + } + generator.insert(name.as_str()); + }); + } + + generator + } + /// Suggest a name without conflicts. If the name conflicts with existing names, /// it will try to resolve the conflict by adding a numeric suffix. pub fn suggest_name(&mut self, name: &str) -> SmolStr {