Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/generate_single_field_struct_from.rs')
| -rw-r--r-- | crates/ide-assists/src/handlers/generate_single_field_struct_from.rs | 51 |
1 files changed, 35 insertions, 16 deletions
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 4e95ceb2e8..a1ec763365 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,18 +1,19 @@ use ast::make; +use hir::next_solver::{DbInterner, TypingMode}; use hir::{HasCrate, ModuleDef, Semantics}; 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, }; +use syntax::syntax_editor::{Element, Position}; use syntax::{ TokenText, - ast::{self, AstNode, HasGenericParams, HasName, edit, edit_in_place::Indent}, + ast::{self, AstNode, HasAttrs, HasGenericParams, HasName, edit::AstNodeEdit}, }; use crate::{ AssistId, assist_context::{AssistContext, Assists}, - utils::add_cfg_attrs_to, }; // Assist: generate_single_field_struct_from @@ -48,6 +49,7 @@ pub(crate) fn generate_single_field_struct_from( let strukt_name = ctx.find_node_at_offset::<ast::Name>()?; let adt = ast::Adt::cast(strukt_name.syntax().parent()?)?; let ast::Adt::Struct(strukt) = adt else { + tracing::debug!(?adt); return None; }; @@ -58,10 +60,12 @@ pub(crate) fn generate_single_field_struct_from( let constructors = make_constructors(ctx, module, &types); if constructors.iter().filter(|expr| expr.is_none()).count() != 1 { + tracing::debug!(?constructors); return None; } let main_field_i = constructors.iter().position(Option::is_none)?; if from_impl_exists(&strukt, main_field_i, &ctx.sema).is_some() { + tracing::debug!(?strukt, ?main_field_i); return None; } @@ -90,6 +94,7 @@ pub(crate) fn generate_single_field_struct_from( let fn_ = make::fn_( None, + None, make::name("from"), None, None, @@ -107,11 +112,14 @@ pub(crate) fn generate_single_field_struct_from( false, false, ) - .clone_for_update(); + .indent(1.into()); - fn_.indent(1.into()); + let cfg_attrs = strukt + .attrs() + .filter(|attr| attr.as_simple_call().is_some_and(|(name, _arg)| name == "cfg")); let impl_ = make::impl_trait( + cfg_attrs, false, None, trait_gen_args, @@ -121,18 +129,25 @@ pub(crate) fn generate_single_field_struct_from( make::ty("From"), ty.clone(), None, - ty_where_clause.map(|wc| edit::AstNodeEdit::reset_indent(&wc)), + ty_where_clause.map(|wc| wc.reset_indent()), None, ) .clone_for_update(); impl_.get_or_create_assoc_item_list().add_item(fn_.into()); + let impl_ = impl_.indent(indent); - add_cfg_attrs_to(&strukt, &impl_); + let mut edit = builder.make_editor(strukt.syntax()); - impl_.reindent_to(indent); + edit.insert_all( + Position::after(strukt.syntax()), + vec![ + make::tokens::whitespace(&format!("\n\n{indent}")).syntax_element(), + impl_.syntax().syntax_element(), + ], + ); - builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}")); + builder.add_file_edits(ctx.vfs_file_id(), edit); }, ) } @@ -163,6 +178,7 @@ fn make_constructors( types: &[ast::Type], ) -> Vec<Option<ast::Expr>> { let (db, sema) = (ctx.db(), &ctx.sema); + let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate())); types .iter() .map(|ty| { @@ -173,11 +189,7 @@ fn make_constructors( let item_in_ns = ModuleDef::Adt(ty.as_adt()?).into(); let edition = module.krate().edition(db); - let ty_path = module.find_path( - db, - item_for_path_search(db, item_in_ns)?, - ctx.config.import_path_config(), - )?; + 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) }) @@ -198,6 +210,7 @@ fn get_fields(strukt: &ast::Struct) -> Option<(Option<Vec<ast::Name>>, Vec<ast:: }) } +#[tracing::instrument(ret)] fn from_impl_exists( strukt: &ast::Struct, main_field_i: usize, @@ -207,9 +220,15 @@ fn from_impl_exists( let strukt = sema.to_def(strukt)?; let krate = strukt.krate(db); let from_trait = FamousDefs(sema, krate).core_convert_From()?; - let ty = strukt.fields(db).get(main_field_i)?.ty(db); - - strukt.ty(db).impls_trait(db, from_trait, &[ty]).then_some(()) + let interner = DbInterner::new_with(db, Some(krate.base()), None); + use hir::next_solver::infer::DbInternerInferExt; + let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); + + let strukt = strukt.instantiate_infer(&infcx); + let field_ty = strukt.fields(db).get(main_field_i)?.ty(db); + let struct_ty = strukt.ty(db); + tracing::debug!(?strukt, ?field_ty, ?struct_ty); + struct_ty.impls_trait(infcx, from_trait, &[field_ty]).then_some(()) } #[cfg(test)] |