Unnamed repository; edit this file 'description' to name the repository.
13 files changed, 180 insertions, 53 deletions
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 3c33ddec31..f2d71a1dfe 100644 --- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -4,7 +4,7 @@ use either::Either; use hir::{Adt, AsAssocItem, Crate, FindPathConfig, HasAttrs, ModuleDef, Semantics}; use ide_db::RootDatabase; use ide_db::syntax_helpers::suggest_name; -use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; +use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast_with_factory}; use itertools::Itertools; use syntax::ast::edit::IndentLevel; use syntax::ast::syntax_factory::SyntaxFactory; @@ -602,7 +602,11 @@ fn build_pat( false, ) } else { - mod_path_to_ast(&module.find_path(db, ModuleDef::from(var), cfg)?, edition) + mod_path_to_ast_with_factory( + make, + &module.find_path(db, ModuleDef::from(var), cfg)?, + edition, + ) }; let fields = var.fields(db); let pat: ast::Pat = match var.kind(db) { diff --git a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs index e88778a62e..231c447ec3 100644 --- a/crates/ide-assists/src/handlers/convert_bool_to_enum.rs +++ b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -5,7 +5,7 @@ use ide_db::{ FxHashSet, assists::AssistId, defs::Definition, - helpers::mod_path_to_ast, + helpers::mod_path_to_ast_with_factory, imports::insert_use::{ImportScope, insert_use}, search::{FileReference, UsageSearchResult}, source_change::SourceChangeBuilder, @@ -373,7 +373,7 @@ fn augment_references_with_imports( ) .map(|mod_path| { make.path_concat( - mod_path_to_ast(&mod_path, edition), + mod_path_to_ast_with_factory(make, &mod_path, edition), make.path_from_text("Bool"), ) })?; 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 e330102423..2fcde15874 100644 --- a/crates/ide-assists/src/handlers/convert_into_to_from.rs +++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs @@ -1,4 +1,6 @@ -use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast, traits::resolve_target_trait}; +use ide_db::{ + famous_defs::FamousDefs, helpers::mod_path_to_ast_with_factory, traits::resolve_target_trait, +}; use syntax::ast::{self, AstNode, HasGenericArgs, HasName}; use crate::{AssistContext, AssistId, Assists}; @@ -44,17 +46,15 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - } let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.sema.db))); + let current_edition = module.krate(ctx.db()).edition(ctx.db()); - let src_type_path = { + let src_type_mod_path = { let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?; let src_type_def = match ctx.sema.resolve_path(&src_type_path) { Some(hir::PathResolution::Def(module_def)) => module_def, _ => return None, }; - mod_path_to_ast( - &module.find_path(ctx.db(), src_type_def, cfg)?, - module.krate(ctx.db()).edition(ctx.db()), - ) + module.find_path(ctx.db(), src_type_def, cfg)? }; let dest_type = match &ast_trait { @@ -89,19 +89,45 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) - "Convert Into to From", impl_.syntax().text_range(), |builder| { - builder.replace(src_type.syntax().text_range(), dest_type.to_string()); - builder.replace(ast_trait.syntax().text_range(), format!("From<{src_type}>")); - builder.replace(into_fn_return.syntax().text_range(), "-> Self"); - builder.replace(into_fn_params.syntax().text_range(), format!("(val: {src_type})")); - builder.replace(into_fn_name.syntax().text_range(), "from"); + let editor = builder.make_editor(impl_.syntax()); + let make = editor.make(); + let src_type_path = + mod_path_to_ast_with_factory(make, &src_type_mod_path, current_edition); + + editor.replace(src_type.syntax(), make.ty(&dest_type.to_string()).syntax()); + editor.replace(ast_trait.syntax(), make.ty(&format!("From<{src_type}>")).syntax()); + editor.replace(into_fn_return.syntax(), make.ret_type(make.ty("Self")).syntax()); + + editor.replace( + into_fn_params.syntax(), + make.param_list( + None, + [make.param(make.simple_ident_pat(make.name("val")).into(), src_type.clone())], + ) + .syntax(), + ); + editor.replace(into_fn_name.syntax(), make.name("from").syntax()); for s in selfs { match s.text().as_ref() { - "self" => builder.replace(s.syntax().text_range(), "val"), - "Self" => builder.replace(s.syntax().text_range(), src_type_path.to_string()), + "self" => editor.replace(s.syntax(), make.name_ref("val").syntax()), + "Self" => { + if let Some(path_segment) = + s.syntax().parent().and_then(ast::PathSegment::cast) + { + let self_path = path_segment.parent_path(); + if self_path.qualifier().is_none() + && path_segment.generic_arg_list().is_none() + { + editor.replace(self_path.syntax(), src_type_path.syntax()); + } + } + } _ => {} } } + + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) } diff --git a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs index 0af0cbc32a..254ff7280f 100644 --- a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs +++ b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs @@ -4,7 +4,7 @@ use ide_db::{ FxHashSet, assists::AssistId, defs::Definition, - helpers::mod_path_to_ast, + helpers::mod_path_to_ast_with_factory, imports::insert_use::{ImportScope, insert_use_with_editor}, search::{FileReference, UsageSearchResult}, source_change::SourceChangeBuilder, @@ -176,7 +176,7 @@ fn node_to_pats(node: SyntaxNode) -> Option<Vec<ast::Pat>> { } fn augment_references_with_imports( - syntax_factory: &SyntaxFactory, + make: &SyntaxFactory, ctx: &AssistContext<'_>, references: &[FileReference], struct_name: &str, @@ -208,12 +208,13 @@ fn augment_references_with_imports( cfg, ) .map(|mod_path| { - syntax_factory.path_concat( - mod_path_to_ast( + make.path_concat( + mod_path_to_ast_with_factory( + make, &mod_path, target_module.krate(ctx.db()).edition(ctx.db()), ), - syntax_factory.path_from_text(struct_name), + make.path_from_text(struct_name), ) }); diff --git a/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 9ffce445d1..6e6c7fcbfb 100644 --- a/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -3,7 +3,7 @@ use ide_db::{ FxHashMap, FxHashSet, RootDatabase, assists::AssistId, defs::Definition, - helpers::mod_path_to_ast, + helpers::mod_path_to_ast_with_factory, search::{FileReference, SearchScope}, }; use itertools::Itertools; @@ -276,7 +276,7 @@ fn destructure_pat( field_names: &[(SmolStr, SmolStr)], ) { let make = editor.make(); - let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition); + let struct_path = mod_path_to_ast_with_factory(make, &data.struct_def_path, data.edition); let is_ref = data.target.is_ref(); let is_mut = data.target.is_mut(); 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 21013e2e61..9a884bc1da 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 @@ -5,7 +5,7 @@ use hir::{EnumVariant, HasCrate, Module, ModuleDef, Name}; use ide_db::{ FxHashSet, RootDatabase, defs::Definition, - helpers::mod_path_to_ast, + helpers::mod_path_to_ast_with_factory, imports::insert_use::{ImportScope, InsertUseConfig, insert_use_with_editor}, path_transform::PathTransform, search::FileReference, @@ -401,7 +401,12 @@ fn apply_references( ) { let make = editor.make(); if let Some((scope, path)) = import { - insert_use_with_editor(&scope, mod_path_to_ast(&path, edition), &insert_use_cfg, editor); + insert_use_with_editor( + &scope, + mod_path_to_ast_with_factory(make, &path, edition), + &insert_use_cfg, + editor, + ); } // deep clone to prevent cycle let path = make.path_from_segments(iter::once(segment.clone()), false); diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index 520709adc5..756dc3d0fa 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -1,6 +1,6 @@ use ide_db::{ imports::import_assets::item_for_path_search, syntax_helpers::suggest_name::NameGenerator, - use_trivial_constructor::use_trivial_constructor, + use_trivial_constructor::use_trivial_constructor_with_factory, }; use syntax::{ ast::{self, AstNode, HasName, HasVisibility, StructKind, edit::AstNodeEdit}, @@ -90,9 +90,10 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option let edition = current_module.krate(ctx.db()).edition(ctx.db()); - let expr = use_trivial_constructor( + let expr = use_trivial_constructor_with_factory( + make, ctx.sema.db, - ide_db::helpers::mod_path_to_ast(&type_path, edition), + ide_db::helpers::mod_path_to_ast_with_factory(make, &type_path, edition), &ty, edition, )?; diff --git a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs index 10c009a2ea..265a632a8c 100644 --- a/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs +++ b/crates/ide-assists/src/handlers/generate_single_field_struct_from.rs @@ -1,8 +1,9 @@ use hir::next_solver::{DbInterner, TypingMode}; use hir::{HasCrate, ModuleDef, Semantics}; +use ide_db::use_trivial_constructor::use_trivial_constructor_with_factory; use ide_db::{ - RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast, - imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor, + RootDatabase, famous_defs::FamousDefs, helpers::mod_path_to_ast_with_factory, + imports::import_assets::item_for_path_search, }; use syntax::syntax_editor::{Position, SyntaxEditor}; use syntax::{ @@ -197,7 +198,13 @@ fn make_constructors( let ty_path = module.find_path(db, item_for_path_search(db, item_in_ns)?, cfg)?; - use_trivial_constructor(db, mod_path_to_ast(&ty_path, edition), &ty, edition) + use_trivial_constructor_with_factory( + &make, + db, + mod_path_to_ast_with_factory(&make, &ty_path, edition), + &ty, + edition, + ) }) .collect() } diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs index e3dd77360c..18a31a2b42 100644 --- a/crates/ide-assists/src/handlers/qualify_path.rs +++ b/crates/ide-assists/src/handlers/qualify_path.rs @@ -4,7 +4,7 @@ use std::iter; use hir::AsAssocItem; use ide_db::RootDatabase; use ide_db::{ - helpers::mod_path_to_ast, + helpers::mod_path_to_ast_with_factory, imports::import_assets::{ImportCandidate, LocatedImport}, }; use syntax::Edition; @@ -129,7 +129,7 @@ impl QualifyCandidate<'_> { item: hir::ItemInNs, edition: Edition, ) { - let import = mod_path_to_ast(import, edition); + let import = mod_path_to_ast_with_factory(editor.make(), import, edition); match self { QualifyCandidate::QualifierStart(segment, generics) => { let generics = generics.as_ref().map_or_else(String::new, ToString::to_string); 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 751cd42f6e..da02d9db40 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 @@ -1,10 +1,13 @@ use hir::{InFile, ModuleDef}; -use ide_db::{helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator}; +use ide_db::{ + helpers::mod_path_to_ast_with_factory, imports::import_assets::NameToImport, items_locator, +}; use itertools::Itertools; use syntax::{ + Edition, SyntaxKind::WHITESPACE, T, - ast::{self, AstNode, HasName}, + ast::{self, AstNode, HasName, syntax_factory::SyntaxFactory}, syntax_editor::{Position, SyntaxEditor}, }; @@ -87,13 +90,12 @@ pub(crate) fn replace_derive_with_manual_impl( .flat_map(|trait_| { current_module .find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), cfg) - .as_ref() - .map(|path| mod_path_to_ast(path, current_edition)) - .zip(Some(trait_)) + .map(|path| (path, trait_)) }); - let mut no_traits_found = true; - for (replace_trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { + let found_traits = found_traits.collect::<Vec<_>>(); + let no_traits_found = found_traits.is_empty(); + for (replace_trait_mod_path, trait_) in found_traits { add_assist( acc, ctx, @@ -101,13 +103,25 @@ pub(crate) fn replace_derive_with_manual_impl( ¤t_derives, &args, &path, - &replace_trait_path, + Some(replace_trait_mod_path), Some(trait_), &adt, + current_edition, )?; } if no_traits_found { - add_assist(acc, ctx, &attr, ¤t_derives, &args, &path, &path, None, &adt)?; + add_assist( + acc, + ctx, + &attr, + ¤t_derives, + &args, + &path, + None, + None, + &adt, + current_edition, + )?; } Some(()) } @@ -119,17 +133,28 @@ fn add_assist( old_derives: &[ast::Path], old_tree: &ast::TokenTree, old_trait_path: &ast::Path, - replace_trait_path: &ast::Path, + replace_trait_mod_path: Option<hir::ModPath>, trait_: Option<hir::Trait>, adt: &ast::Adt, + current_edition: Edition, ) -> Option<()> { let target = attr.syntax().text_range(); let annotated_name = adt.name()?; - let label = format!("Convert to manual `impl {replace_trait_path} for {annotated_name}`"); + let label_trait_path = match replace_trait_mod_path.as_ref() { + Some(path) => { + mod_path_to_ast_with_factory(&SyntaxFactory::without_mappings(), path, current_edition) + } + None => old_trait_path.clone(), + }; + let label = format!("Convert to manual `impl {label_trait_path} for {annotated_name}`"); acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| { let editor = builder.make_editor(attr.syntax()); let make = editor.make(); + let replace_trait_path = match replace_trait_mod_path.as_ref() { + Some(path) => mod_path_to_ast_with_factory(make, path, current_edition), + None => old_trait_path.clone(), + }; let insert_after = Position::after(adt.syntax()); let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false); let impl_def = impl_def_from_trait( @@ -139,7 +164,7 @@ fn add_assist( adt, &annotated_name, trait_, - replace_trait_path, + &replace_trait_path, impl_is_unsafe, ); update_attribute(&editor, old_derives, old_tree, old_trait_path, attr); diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index 2d4a6b8b5b..e66f645c00 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -1,6 +1,6 @@ //! See [`PathTransform`]. -use crate::helpers::mod_path_to_ast; +use crate::helpers::mod_path_to_ast_with_factory; use either::Either; use hir::{ AsAssocItem, FindPathConfig, HirDisplay, HirFileId, ModuleDef, SemanticsScope, @@ -354,6 +354,7 @@ impl Ctx<'_> { } fn transform_path_(&self, editor: &SyntaxEditor, path: &ast::Path) -> Option<()> { + let make = editor.make(); if path.qualifier().is_some() { return None; } @@ -397,7 +398,14 @@ impl Ctx<'_> { hir::ModuleDef::Trait(trait_ref), cfg, )?; - match make::ty_path(mod_path_to_ast(&found_path, self.target_edition)) { + match make + .ty_path(mod_path_to_ast_with_factory( + make, + &found_path, + self.target_edition, + )) + .into() + { ast::Type::PathType(path_ty) => Some(path_ty), _ => None, } @@ -447,7 +455,7 @@ impl Ctx<'_> { allow_unstable: true, }; let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?; - let res = mod_path_to_ast(&found_path, self.target_edition); + let res = mod_path_to_ast_with_factory(make, &found_path, self.target_edition); let (res_editor, res) = SyntaxEditor::with_ast_node(&res); if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) && let Some(segment) = res.segment() @@ -501,7 +509,8 @@ impl Ctx<'_> { )?; if let Some(qual) = - mod_path_to_ast(&found_path, self.target_edition).qualifier() + mod_path_to_ast_with_factory(make, &found_path, self.target_edition) + .qualifier() { editor.replace( path.syntax(), @@ -524,8 +533,9 @@ impl Ctx<'_> { fn transform_ident_pat(&self, editor: &SyntaxEditor, ident_pat: &ast::IdentPat) -> Option<()> { let name = ident_pat.name()?; + let make = editor.make(); - let temp_path = make::path_from_text(&name.text()); + let temp_path = make.path_from_text(&name.text()); let resolution = self.source_scope.speculative_resolve(&temp_path)?; @@ -580,7 +590,7 @@ impl Ctx<'_> { let found_path = self.target_module.find_path(self.source_scope.db, def, cfg)?; editor.replace( ident_pat.syntax(), - mod_path_to_ast(&found_path, self.target_edition).syntax(), + mod_path_to_ast_with_factory(make, &found_path, self.target_edition).syntax(), ); Some(()) } diff --git a/crates/ide-db/src/use_trivial_constructor.rs b/crates/ide-db/src/use_trivial_constructor.rs index a91d436afc..0b94a1fa5a 100644 --- a/crates/ide-db/src/use_trivial_constructor.rs +++ b/crates/ide-db/src/use_trivial_constructor.rs @@ -4,7 +4,7 @@ use hir::StructKind; use span::Edition; use syntax::{ ToSmolStr, - ast::{Expr, Path, make}, + ast::{Expr, Path, make, syntax_factory::SyntaxFactory}, }; /// given a type return the trivial constructor (if one exists) @@ -37,3 +37,34 @@ pub fn use_trivial_constructor( None } + +pub fn use_trivial_constructor_with_factory( + make: &SyntaxFactory, + db: &crate::RootDatabase, + path: Path, + ty: &hir::Type<'_>, + edition: Edition, +) -> Option<Expr> { + match ty.as_adt() { + Some(hir::Adt::Enum(x)) => { + if let &[variant] = &*x.variants(db) + && variant.kind(db) == hir::StructKind::Unit + { + let path = make.path_qualified( + path, + make.path_segment( + make.name_ref(&variant.name(db).display_no_db(edition).to_smolstr()), + ), + ); + + return Some(make.expr_path(path)); + } + } + Some(hir::Adt::Struct(x)) if x.kind(db) == StructKind::Unit => { + return Some(make.expr_path(path)); + } + _ => {} + } + + None +} diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs index bc4a825987..b9106408b3 100644 --- a/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -671,6 +671,23 @@ impl SyntaxFactory { ast } + pub fn path_qualified(&self, qual: ast::Path, segment: ast::PathSegment) -> ast::Path { + let ast = make::path_qualified(qual.clone(), segment.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(out_qual) = ast.qualifier() { + builder.map_node(qual.syntax().clone(), out_qual.syntax().clone()); + } + if let Some(out_segment) = ast.segment() { + builder.map_node(segment.syntax().clone(), out_segment.syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } + pub fn path_from_segments( &self, segments: impl IntoIterator<Item = ast::PathSegment>, |