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.rs51
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)]