mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
1001 lines
26 KiB
Rust
1001 lines
26 KiB
Rust
use ast::make;
|
|
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::{
|
|
TokenText,
|
|
ast::{self, AstNode, HasGenericParams, HasName, edit, edit_in_place::Indent},
|
|
};
|
|
|
|
use crate::{
|
|
AssistId,
|
|
assist_context::{AssistContext, Assists},
|
|
utils::add_cfg_attrs_to,
|
|
};
|
|
|
|
// Assist: generate_single_field_struct_from
|
|
//
|
|
// Implement From for a single field structure, ignore trivial types.
|
|
//
|
|
// ```
|
|
// # //- minicore: from, phantom_data
|
|
// use core::marker::PhantomData;
|
|
// struct $0Foo<T> {
|
|
// id: i32,
|
|
// _phantom_data: PhantomData<T>,
|
|
// }
|
|
// ```
|
|
// ->
|
|
// ```
|
|
// use core::marker::PhantomData;
|
|
// struct Foo<T> {
|
|
// id: i32,
|
|
// _phantom_data: PhantomData<T>,
|
|
// }
|
|
//
|
|
// impl<T> From<i32> for Foo<T> {
|
|
// fn from(id: i32) -> Self {
|
|
// Self { id, _phantom_data: PhantomData }
|
|
// }
|
|
// }
|
|
// ```
|
|
pub(crate) fn generate_single_field_struct_from(
|
|
acc: &mut Assists,
|
|
ctx: &AssistContext<'_>,
|
|
) -> Option<()> {
|
|
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 {
|
|
return None;
|
|
};
|
|
|
|
let sema = &ctx.sema;
|
|
let (names, types) = get_fields(&strukt)?;
|
|
|
|
let module = sema.scope(strukt.syntax())?.module();
|
|
let constructors = make_constructors(ctx, module, &types);
|
|
|
|
if constructors.iter().filter(|expr| expr.is_none()).count() != 1 {
|
|
return None;
|
|
}
|
|
let main_field_i = constructors.iter().position(Option::is_none)?;
|
|
if from_impl_exists(&strukt, main_field_i, &ctx.sema).is_some() {
|
|
return None;
|
|
}
|
|
|
|
let main_field_name =
|
|
names.as_ref().map_or(TokenText::borrowed("value"), |names| names[main_field_i].text());
|
|
let main_field_ty = types[main_field_i].clone();
|
|
|
|
acc.add(
|
|
AssistId::generate("generate_single_field_struct_from"),
|
|
"Generate single field `From`",
|
|
strukt.syntax().text_range(),
|
|
|builder| {
|
|
let indent = strukt.indent_level();
|
|
let ty_where_clause = strukt.where_clause();
|
|
let type_gen_params = strukt.generic_param_list();
|
|
let type_gen_args = type_gen_params.as_ref().map(|params| params.to_generic_args());
|
|
let trait_gen_args = Some(make::generic_arg_list([ast::GenericArg::TypeArg(
|
|
make::type_arg(main_field_ty.clone()),
|
|
)]));
|
|
|
|
let ty = make::ty(&strukt_name.text());
|
|
|
|
let constructor =
|
|
make_adt_constructor(names.as_deref(), constructors, &main_field_name);
|
|
let body = make::block_expr([], Some(constructor));
|
|
|
|
let fn_ = make::fn_(
|
|
None,
|
|
make::name("from"),
|
|
None,
|
|
None,
|
|
make::param_list(
|
|
None,
|
|
[make::param(
|
|
make::path_pat(make::path_from_text(&main_field_name)),
|
|
main_field_ty,
|
|
)],
|
|
),
|
|
body,
|
|
Some(make::ret_type(make::ty("Self"))),
|
|
false,
|
|
false,
|
|
false,
|
|
false,
|
|
)
|
|
.clone_for_update();
|
|
|
|
fn_.indent(1.into());
|
|
|
|
let impl_ = make::impl_trait(
|
|
false,
|
|
None,
|
|
trait_gen_args,
|
|
type_gen_params,
|
|
type_gen_args,
|
|
false,
|
|
make::ty("From"),
|
|
ty.clone(),
|
|
None,
|
|
ty_where_clause.map(|wc| edit::AstNodeEdit::reset_indent(&wc)),
|
|
None,
|
|
)
|
|
.clone_for_update();
|
|
|
|
impl_.get_or_create_assoc_item_list().add_item(fn_.into());
|
|
|
|
add_cfg_attrs_to(&strukt, &impl_);
|
|
|
|
impl_.reindent_to(indent);
|
|
|
|
builder.insert(strukt.syntax().text_range().end(), format!("\n\n{indent}{impl_}"));
|
|
},
|
|
)
|
|
}
|
|
|
|
fn make_adt_constructor(
|
|
names: Option<&[ast::Name]>,
|
|
constructors: Vec<Option<ast::Expr>>,
|
|
main_field_name: &TokenText<'_>,
|
|
) -> ast::Expr {
|
|
if let Some(names) = names {
|
|
let fields = make::record_expr_field_list(names.iter().zip(constructors).map(
|
|
|(name, initializer)| {
|
|
make::record_expr_field(make::name_ref(&name.text()), initializer)
|
|
},
|
|
));
|
|
make::record_expr(make::path_from_text("Self"), fields).into()
|
|
} else {
|
|
let arg_list = make::arg_list(constructors.into_iter().map(|expr| {
|
|
expr.unwrap_or_else(|| make::expr_path(make::path_from_text(main_field_name)))
|
|
}));
|
|
make::expr_call(make::expr_path(make::path_from_text("Self")), arg_list).into()
|
|
}
|
|
}
|
|
|
|
fn make_constructors(
|
|
ctx: &AssistContext<'_>,
|
|
module: hir::Module,
|
|
types: &[ast::Type],
|
|
) -> Vec<Option<ast::Expr>> {
|
|
let (db, sema) = (ctx.db(), &ctx.sema);
|
|
types
|
|
.iter()
|
|
.map(|ty| {
|
|
let ty = sema.resolve_type(ty)?;
|
|
if ty.is_unit() {
|
|
return Some(make::expr_tuple([]).into());
|
|
}
|
|
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(),
|
|
)?;
|
|
|
|
use_trivial_constructor(db, mod_path_to_ast(&ty_path, edition), &ty, edition)
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn get_fields(strukt: &ast::Struct) -> Option<(Option<Vec<ast::Name>>, Vec<ast::Type>)> {
|
|
Some(match strukt.kind() {
|
|
ast::StructKind::Unit => return None,
|
|
ast::StructKind::Record(fields) => {
|
|
let names = fields.fields().map(|field| field.name()).collect::<Option<_>>()?;
|
|
let types = fields.fields().map(|field| field.ty()).collect::<Option<_>>()?;
|
|
(Some(names), types)
|
|
}
|
|
ast::StructKind::Tuple(fields) => {
|
|
(None, fields.fields().map(|field| field.ty()).collect::<Option<_>>()?)
|
|
}
|
|
})
|
|
}
|
|
|
|
fn from_impl_exists(
|
|
strukt: &ast::Struct,
|
|
main_field_i: usize,
|
|
sema: &Semantics<'_, RootDatabase>,
|
|
) -> Option<()> {
|
|
let db = sema.db;
|
|
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(())
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::tests::{check_assist, check_assist_not_applicable};
|
|
|
|
use super::generate_single_field_struct_from;
|
|
|
|
#[test]
|
|
fn works() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo {
|
|
foo: i32,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo {
|
|
foo: i32,
|
|
}
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(foo: i32) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from, phantom_data
|
|
struct $0Foo {
|
|
b1: (),
|
|
b2: core::marker::PhantomData,
|
|
foo: i32,
|
|
a1: (),
|
|
a2: core::marker::PhantomData,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo {
|
|
b1: (),
|
|
b2: core::marker::PhantomData,
|
|
foo: i32,
|
|
a1: (),
|
|
a2: core::marker::PhantomData,
|
|
}
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(foo: i32) -> Self {
|
|
Self { b1: (), b2: core::marker::PhantomData, foo, a1: (), a2: core::marker::PhantomData }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn cfgs() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
#[cfg(feature = "foo")]
|
|
#[cfg(test)]
|
|
struct $0Foo {
|
|
foo: i32,
|
|
}
|
|
"#,
|
|
r#"
|
|
#[cfg(feature = "foo")]
|
|
#[cfg(test)]
|
|
struct Foo {
|
|
foo: i32,
|
|
}
|
|
|
|
#[cfg(feature = "foo")]
|
|
#[cfg(test)]
|
|
impl From<i32> for Foo {
|
|
fn from(foo: i32) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn indent() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
mod foo {
|
|
struct $0Foo {
|
|
foo: i32,
|
|
}
|
|
}
|
|
"#,
|
|
r#"
|
|
mod foo {
|
|
struct Foo {
|
|
foo: i32,
|
|
}
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(foo: i32) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
mod foo {
|
|
mod bar {
|
|
struct $0Foo {
|
|
foo: i32,
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
r#"
|
|
mod foo {
|
|
mod bar {
|
|
struct Foo {
|
|
foo: i32,
|
|
}
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(foo: i32) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn where_clause_indent() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
mod foo {
|
|
mod bar {
|
|
trait Trait {}
|
|
struct $0Foo<T>
|
|
where
|
|
T: Trait,
|
|
{
|
|
foo: T,
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
r#"
|
|
mod foo {
|
|
mod bar {
|
|
trait Trait {}
|
|
struct Foo<T>
|
|
where
|
|
T: Trait,
|
|
{
|
|
foo: T,
|
|
}
|
|
|
|
impl<T> From<T> for Foo<T>
|
|
where
|
|
T: Trait,
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
mod foo {
|
|
mod bar {
|
|
trait Trait<const B: bool> {}
|
|
struct $0Foo<T>
|
|
where
|
|
T: Trait<{
|
|
true
|
|
}>
|
|
{
|
|
foo: T,
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
r#"
|
|
mod foo {
|
|
mod bar {
|
|
trait Trait<const B: bool> {}
|
|
struct Foo<T>
|
|
where
|
|
T: Trait<{
|
|
true
|
|
}>
|
|
{
|
|
foo: T,
|
|
}
|
|
|
|
impl<T> From<T> for Foo<T>
|
|
where
|
|
T: Trait<{
|
|
true
|
|
}>
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn generics() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T> {
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T> {
|
|
foo: T,
|
|
}
|
|
|
|
impl<T> From<T> for Foo<T> {
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send> {
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send> {
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send> From<T> for Foo<T> {
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send> where T: Sync,{
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send> where T: Sync,{
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send> From<T> for Foo<T>
|
|
where T: Sync,
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send> where T: Sync {
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send> where T: Sync {
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send> From<T> for Foo<T>
|
|
where T: Sync
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send> where T: Sync, Self: Send {
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send> where T: Sync, Self: Send {
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send> From<T> for Foo<T>
|
|
where T: Sync, Self: Send
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send>
|
|
where T: Sync, Self: Send
|
|
{
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send>
|
|
where T: Sync, Self: Send
|
|
{
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send> From<T> for Foo<T>
|
|
where T: Sync, Self: Send
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send>
|
|
where T: Sync, Self: Send,
|
|
{
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send>
|
|
where T: Sync, Self: Send,
|
|
{
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send> From<T> for Foo<T>
|
|
where T: Sync, Self: Send,
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send>
|
|
where T: Sync,
|
|
Self: Send,
|
|
{
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send>
|
|
where T: Sync,
|
|
Self: Send,
|
|
{
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send> From<T> for Foo<T>
|
|
where T: Sync,
|
|
Self: Send,
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send>
|
|
where
|
|
T: Sync,
|
|
Self: Send,
|
|
{
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send>
|
|
where
|
|
T: Sync,
|
|
Self: Send,
|
|
{
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send> From<T> for Foo<T>
|
|
where
|
|
T: Sync,
|
|
Self: Send,
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T: Send + Sync>
|
|
where
|
|
T: Sync,
|
|
Self: Send,
|
|
{
|
|
foo: T,
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo<T: Send + Sync>
|
|
where
|
|
T: Sync,
|
|
Self: Send,
|
|
{
|
|
foo: T,
|
|
}
|
|
|
|
impl<T: Send + Sync> From<T> for Foo<T>
|
|
where
|
|
T: Sync,
|
|
Self: Send,
|
|
{
|
|
fn from(foo: T) -> Self {
|
|
Self { foo }
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn tuple() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo(i32);
|
|
"#,
|
|
r#"
|
|
struct Foo(i32);
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T>(T);
|
|
"#,
|
|
r#"
|
|
struct Foo<T>(T);
|
|
|
|
impl<T> From<T> for Foo<T> {
|
|
fn from(value: T) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn trivial() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from, phantom_data
|
|
use core::marker::PhantomData;
|
|
struct $0Foo(i32, PhantomData<i32>);
|
|
"#,
|
|
r#"
|
|
use core::marker::PhantomData;
|
|
struct Foo(i32, PhantomData<i32>);
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self(value, PhantomData)
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from, phantom_data
|
|
use core::marker::PhantomData;
|
|
struct $0Foo(i32, PhantomData<()>);
|
|
"#,
|
|
r#"
|
|
use core::marker::PhantomData;
|
|
struct Foo(i32, PhantomData<()>);
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self(value, PhantomData)
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from, phantom_data
|
|
use core::marker::PhantomData;
|
|
struct $0Foo(PhantomData<()>, i32, PhantomData<()>);
|
|
"#,
|
|
r#"
|
|
use core::marker::PhantomData;
|
|
struct Foo(PhantomData<()>, i32, PhantomData<()>);
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self(PhantomData, value, PhantomData)
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from, phantom_data
|
|
use core::marker::PhantomData;
|
|
struct $0Foo<T>(PhantomData<T>, i32, PhantomData<()>);
|
|
"#,
|
|
r#"
|
|
use core::marker::PhantomData;
|
|
struct Foo<T>(PhantomData<T>, i32, PhantomData<()>);
|
|
|
|
impl<T> From<i32> for Foo<T> {
|
|
fn from(value: i32) -> Self {
|
|
Self(PhantomData, value, PhantomData)
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn unit() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo(i32, ());
|
|
"#,
|
|
r#"
|
|
struct Foo(i32, ());
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self(value, ())
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo((), i32, ());
|
|
"#,
|
|
r#"
|
|
struct Foo((), i32, ());
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self((), value, ())
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo((), (), i32, ());
|
|
"#,
|
|
r#"
|
|
struct Foo((), (), i32, ());
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self((), (), value, ())
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_multiple_main_field() {
|
|
check_assist_not_applicable(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo(i32, i32);
|
|
"#,
|
|
);
|
|
check_assist_not_applicable(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T>(i32, T);
|
|
"#,
|
|
);
|
|
check_assist_not_applicable(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T>(T, T);
|
|
"#,
|
|
);
|
|
check_assist_not_applicable(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo<T> { foo: T, bar: i32 }
|
|
"#,
|
|
);
|
|
check_assist_not_applicable(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo { foo: i32, bar: i64 }
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn exists_other_from() {
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo(i32);
|
|
|
|
impl From<&i32> for Foo {
|
|
fn from(value: &i32) -> Self {
|
|
todo!()
|
|
}
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo(i32);
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
|
|
impl From<&i32> for Foo {
|
|
fn from(value: &i32) -> Self {
|
|
todo!()
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo(i32);
|
|
|
|
type X = i32;
|
|
|
|
impl From<&X> for Foo {
|
|
fn from(value: &X) -> Self {
|
|
todo!()
|
|
}
|
|
}
|
|
"#,
|
|
r#"
|
|
struct Foo(i32);
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(value: i32) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
|
|
type X = i32;
|
|
|
|
impl From<&X> for Foo {
|
|
fn from(value: &X) -> Self {
|
|
todo!()
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn exists_from() {
|
|
check_assist_not_applicable(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo(i32);
|
|
|
|
impl From<i32> for Foo {
|
|
fn from(_: i32) -> Self {
|
|
todo!()
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
check_assist_not_applicable(
|
|
generate_single_field_struct_from,
|
|
r#"
|
|
//- minicore: from
|
|
struct $0Foo(i32);
|
|
|
|
type X = i32;
|
|
|
|
impl From<X> for Foo {
|
|
fn from(_: X) -> Self {
|
|
todo!()
|
|
}
|
|
}
|
|
"#,
|
|
);
|
|
}
|
|
}
|