From 8e3bbaa57b12904b88ff17ffca3bc3e44ebf772c Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 15 Jun 2022 02:41:28 +0200 Subject: [PATCH 1/9] instanciate_empty_structs --- .../ide-assists/src/handlers/generate_new.rs | 100 +++++++++++++++++- .../src/handlers/missing_fields.rs | 83 ++++++++++++++- 2 files changed, 179 insertions(+), 4 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index 6a1f710f6d5..fc17c5626e1 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -1,3 +1,4 @@ +use ide_db::imports::import_assets::item_for_path_search; use itertools::Itertools; use stdx::format_to; use syntax::ast::{self, AstNode, HasName, HasVisibility, StructKind}; @@ -7,6 +8,58 @@ use crate::{ AssistContext, AssistId, AssistKind, Assists, }; +// TODO: how to depupicate with `ide-diagnostics/mssing_fields` +pub fn use_trivial_constructor( + db: &ide_db::RootDatabase, + path: ast::Path, + ty: &hir::Type, +) -> Option { + match ty.as_adt() { + Some(hir::Adt::Enum(x)) => { + let variants = x.variants(db); + + if variants.len() == 1 { + let variant = variants[0]; + + if variant.fields(db).is_empty() { + let path = ast::make::path_qualified( + path, + syntax::ast::make::path_segment(ast::make::name_ref( + &variant.name(db).to_smol_str(), + )), + ); + + use hir::StructKind::*; + let is_record = match variant.kind(db) { + Record => true, + Tuple => false, + Unit => false, + }; + + return Some(if is_record { + ast::Expr::RecordExpr(syntax::ast::make::record_expr( + path, + ast::make::record_expr_field_list(std::iter::empty()), + )) + } else { + syntax::ast::make::expr_path(path) + }); + } + } + } + Some(hir::Adt::Struct(x)) => { + let fields = x.fields(db); + + if fields.is_empty() { + return Some(syntax::ast::make::expr_path(path)); + } + } + _ => {} + } + + None +} + // Assist: generate_new // // Adds a new inherent impl for a type. @@ -48,11 +101,54 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); + let current_module = ctx.sema.scope(strukt.syntax()).unwrap().module(); + + let trivial_constructors = field_list + .fields() + .map(|f| { + let ty = ctx.sema.resolve_type(&f.ty()?)?; + + let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?)); + + let type_path = current_module + .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?; + + let expr = use_trivial_constructor( + &ctx.sema.db, + ide_db::helpers::mod_path_to_ast(&type_path), + &ty, + )?; + + Some(format!("{}: {}", f.name()?.syntax(), expr)) + }) + .collect::>(); + + dbg!(&trivial_constructors); + let params = field_list .fields() - .filter_map(|f| Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax()))) + .enumerate() + .filter_map(|(i, f)| { + if trivial_constructors[i].is_none() { + Some(format!("{}: {}", f.name()?.syntax(), f.ty()?.syntax())) + } else { + None + } + }) + .format(", "); + + let fields = field_list + .fields() + .enumerate() + .filter_map(|(i, f)| { + let contructor = trivial_constructors[i].clone(); + if contructor.is_some() { + contructor + } else { + Some(f.name()?.to_string()) + } + }) .format(", "); - let fields = field_list.fields().filter_map(|f| f.name()).format(", "); format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 891547aaef5..ff7d8de8fdc 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -3,7 +3,10 @@ use hir::{ db::{AstDatabase, HirDatabase}, known, AssocItem, HirDisplay, InFile, Type, }; -use ide_db::{assists::Assist, famous_defs::FamousDefs, source_change::SourceChange, FxHashMap}; +use ide_db::{ + assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search, + source_change::SourceChange, FxHashMap, +}; use stdx::format_to; use syntax::{ algo, @@ -14,6 +17,58 @@ use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticsContext}; +// TODO: how to depupicate with `ide-assists/generate_new` +pub fn use_trivial_constructor( + db: &ide_db::RootDatabase, + path: ast::Path, + ty: &hir::Type, +) -> Option { + match ty.as_adt() { + Some(hir::Adt::Enum(x)) => { + let variants = x.variants(db); + + if variants.len() == 1 { + let variant = variants[0]; + + if variant.fields(db).is_empty() { + let path = ast::make::path_qualified( + path, + syntax::ast::make::path_segment(ast::make::name_ref( + &variant.name(db).to_smol_str(), + )), + ); + + use hir::StructKind::*; + let is_record = match variant.kind(db) { + Record => true, + Tuple => false, + Unit => false, + }; + + return Some(if is_record { + ast::Expr::RecordExpr(syntax::ast::make::record_expr( + path, + ast::make::record_expr_field_list(std::iter::empty()), + )) + } else { + syntax::ast::make::expr_path(path) + }); + } + } + } + Some(hir::Adt::Struct(x)) => { + let fields = x.fields(db); + + if fields.is_empty() { + return Some(syntax::ast::make::expr_path(path)); + } + } + _ => {} + } + + None +} + // Diagnostic: missing-fields // // This diagnostic is triggered if record lacks some fields that exist in the corresponding structure. @@ -55,6 +110,11 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option ctx.sema.scope(ptr.to_node(&root).syntax()).unwrap().module(), + Either::Right(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).unwrap().module(), + }; + let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| { let edit = { let mut builder = TextEdit::builder(); @@ -110,7 +170,26 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option Option { + let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?)); + + let type_path = current_module.find_use_path( + ctx.sema.db, + item_for_path_search(ctx.sema.db, item_in_ns)?, + )?; + + use_trivial_constructor( + &ctx.sema.db, + ide_db::helpers::mod_path_to_ast(&type_path), + &ty, + ) + })(); + + if expr.is_some() { + expr + } else { + Some(generate_fill_expr(ty)) + } }; let field = make::record_expr_field( make::name_ref(&f.name(ctx.sema.db).to_smol_str()), From 8cac16b62e73a9be5c3350a2bddadd8902454797 Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 15 Jun 2022 02:59:32 +0200 Subject: [PATCH 2/9] cleanup --- crates/ide-assists/src/handlers/generate_new.rs | 11 ++--------- crates/ide-diagnostics/src/handlers/missing_fields.rs | 11 ++--------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index fc17c5626e1..31e36a51e8d 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -29,12 +29,7 @@ pub fn use_trivial_constructor( )), ); - use hir::StructKind::*; - let is_record = match variant.kind(db) { - Record => true, - Tuple => false, - Unit => false, - }; + let is_record = variant.kind(db) == hir::StructKind::Record; return Some(if is_record { ast::Expr::RecordExpr(syntax::ast::make::record_expr( @@ -48,9 +43,7 @@ pub fn use_trivial_constructor( } } Some(hir::Adt::Struct(x)) => { - let fields = x.fields(db); - - if fields.is_empty() { + if x.fields(db).is_empty() { return Some(syntax::ast::make::expr_path(path)); } } diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index ff7d8de8fdc..5739a878538 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -38,12 +38,7 @@ pub fn use_trivial_constructor( )), ); - use hir::StructKind::*; - let is_record = match variant.kind(db) { - Record => true, - Tuple => false, - Unit => false, - }; + let is_record = variant.kind(db) == hir::StructKind::Record; return Some(if is_record { ast::Expr::RecordExpr(syntax::ast::make::record_expr( @@ -57,9 +52,7 @@ pub fn use_trivial_constructor( } } Some(hir::Adt::Struct(x)) => { - let fields = x.fields(db); - - if fields.is_empty() { + if x.fields(db).is_empty() { return Some(syntax::ast::make::expr_path(path)); } } From 6a28cccaee6aedf73d94c8a455ad286b9d669f11 Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 15 Jun 2022 03:00:43 +0200 Subject: [PATCH 3/9] remove dbg --- crates/ide-assists/src/handlers/generate_new.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index 31e36a51e8d..4182cc9ba27 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -116,8 +116,6 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> }) .collect::>(); - dbg!(&trivial_constructors); - let params = field_list .fields() .enumerate() From dd0981e3bca20f5660cf13a20bd613d336db155f Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 15 Jun 2022 03:07:26 +0200 Subject: [PATCH 4/9] fix CI --- crates/ide-assists/src/handlers/generate_new.rs | 2 +- crates/ide-diagnostics/src/handlers/missing_fields.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index 4182cc9ba27..d7b05a9ef94 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -9,7 +9,7 @@ use crate::{ }; // TODO: how to depupicate with `ide-diagnostics/mssing_fields` -pub fn use_trivial_constructor( +fn use_trivial_constructor( db: &ide_db::RootDatabase, path: ast::Path, ty: &hir::Type, diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 5739a878538..67692676b44 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -18,7 +18,7 @@ use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticsContext}; // TODO: how to depupicate with `ide-assists/generate_new` -pub fn use_trivial_constructor( +fn use_trivial_constructor( db: &ide_db::RootDatabase, path: ast::Path, ty: &hir::Type, From f52f5fed1149d5655224d3f23e45d90e2957da44 Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 15 Jun 2022 03:16:59 +0200 Subject: [PATCH 5/9] replace TODO with FIXME --- crates/ide-assists/src/handlers/generate_new.rs | 2 +- crates/ide-diagnostics/src/handlers/missing_fields.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index d7b05a9ef94..85d450f7c93 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -8,7 +8,7 @@ use crate::{ AssistContext, AssistId, AssistKind, Assists, }; -// TODO: how to depupicate with `ide-diagnostics/mssing_fields` +// FIXME: how to depupicate with `ide-diagnostics/mssing_fields` fn use_trivial_constructor( db: &ide_db::RootDatabase, path: ast::Path, diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 67692676b44..a27b3273bcc 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -17,7 +17,7 @@ use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticsContext}; -// TODO: how to depupicate with `ide-assists/generate_new` +// FIXME: how to depupicate with `ide-assists/generate_new` fn use_trivial_constructor( db: &ide_db::RootDatabase, path: ast::Path, From f780145c4a66af76bde7b07f24fb8f0bf81e1118 Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 22 Jun 2022 16:29:59 +0200 Subject: [PATCH 6/9] apply suggestions --- .../ide-assists/src/handlers/generate_new.rs | 53 ++----------------- crates/ide-db/src/lib.rs | 1 + .../src/handlers/missing_fields.rs | 53 ++----------------- 3 files changed, 10 insertions(+), 97 deletions(-) diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index 85d450f7c93..4ed241f1af5 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -1,4 +1,6 @@ -use ide_db::imports::import_assets::item_for_path_search; +use ide_db::{ + imports::import_assets::item_for_path_search, use_trivial_contructor::use_trivial_constructor, +}; use itertools::Itertools; use stdx::format_to; use syntax::ast::{self, AstNode, HasName, HasVisibility, StructKind}; @@ -8,51 +10,6 @@ use crate::{ AssistContext, AssistId, AssistKind, Assists, }; -// FIXME: how to depupicate with `ide-diagnostics/mssing_fields` -fn use_trivial_constructor( - db: &ide_db::RootDatabase, - path: ast::Path, - ty: &hir::Type, -) -> Option { - match ty.as_adt() { - Some(hir::Adt::Enum(x)) => { - let variants = x.variants(db); - - if variants.len() == 1 { - let variant = variants[0]; - - if variant.fields(db).is_empty() { - let path = ast::make::path_qualified( - path, - syntax::ast::make::path_segment(ast::make::name_ref( - &variant.name(db).to_smol_str(), - )), - ); - - let is_record = variant.kind(db) == hir::StructKind::Record; - - return Some(if is_record { - ast::Expr::RecordExpr(syntax::ast::make::record_expr( - path, - ast::make::record_expr_field_list(std::iter::empty()), - )) - } else { - syntax::ast::make::expr_path(path) - }); - } - } - } - Some(hir::Adt::Struct(x)) => { - if x.fields(db).is_empty() { - return Some(syntax::ast::make::expr_path(path)); - } - } - _ => {} - } - - None -} - // Assist: generate_new // // Adds a new inherent impl for a type. @@ -84,6 +41,8 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> // Return early if we've found an existing new fn let impl_def = find_struct_impl(ctx, &ast::Adt::Struct(strukt.clone()), "new")?; + let current_module = ctx.sema.scope(strukt.syntax())?.module(); + let target = strukt.syntax().text_range(); acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| { let mut buf = String::with_capacity(512); @@ -94,8 +53,6 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); - let current_module = ctx.sema.scope(strukt.syntax()).unwrap().module(); - let trivial_constructors = field_list .fields() .map(|f| { diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs index 8fad4ac0f3c..165b98d72ed 100644 --- a/crates/ide-db/src/lib.rs +++ b/crates/ide-db/src/lib.rs @@ -20,6 +20,7 @@ pub mod source_change; pub mod symbol_index; pub mod traits; pub mod ty_filter; +pub mod use_trivial_contructor; pub mod imports { pub mod import_assets; diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index a27b3273bcc..828d9229821 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -5,7 +5,7 @@ use hir::{ }; use ide_db::{ assists::Assist, famous_defs::FamousDefs, imports::import_assets::item_for_path_search, - source_change::SourceChange, FxHashMap, + source_change::SourceChange, use_trivial_contructor::use_trivial_constructor, FxHashMap, }; use stdx::format_to; use syntax::{ @@ -17,51 +17,6 @@ use text_edit::TextEdit; use crate::{fix, Diagnostic, DiagnosticsContext}; -// FIXME: how to depupicate with `ide-assists/generate_new` -fn use_trivial_constructor( - db: &ide_db::RootDatabase, - path: ast::Path, - ty: &hir::Type, -) -> Option { - match ty.as_adt() { - Some(hir::Adt::Enum(x)) => { - let variants = x.variants(db); - - if variants.len() == 1 { - let variant = variants[0]; - - if variant.fields(db).is_empty() { - let path = ast::make::path_qualified( - path, - syntax::ast::make::path_segment(ast::make::name_ref( - &variant.name(db).to_smol_str(), - )), - ); - - let is_record = variant.kind(db) == hir::StructKind::Record; - - return Some(if is_record { - ast::Expr::RecordExpr(syntax::ast::make::record_expr( - path, - ast::make::record_expr_field_list(std::iter::empty()), - )) - } else { - syntax::ast::make::expr_path(path) - }); - } - } - } - Some(hir::Adt::Struct(x)) => { - if x.fields(db).is_empty() { - return Some(syntax::ast::make::expr_path(path)); - } - } - _ => {} - } - - None -} - // Diagnostic: missing-fields // // This diagnostic is triggered if record lacks some fields that exist in the corresponding structure. @@ -104,8 +59,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option ctx.sema.scope(ptr.to_node(&root).syntax()).unwrap().module(), - Either::Right(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).unwrap().module(), + Either::Left(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()), + Either::Right(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()), }; let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| { @@ -166,7 +121,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option Option { let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?)); - let type_path = current_module.find_use_path( + let type_path = current_module?.find_use_path( ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?, )?; From f9379df630c860619813f3a2466f30b4b2c1a60b Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 22 Jun 2022 16:34:01 +0200 Subject: [PATCH 7/9] add use_trivial_contructor.rs --- crates/ide-db/src/use_trivial_contructor.rs | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 crates/ide-db/src/use_trivial_contructor.rs diff --git a/crates/ide-db/src/use_trivial_contructor.rs b/crates/ide-db/src/use_trivial_contructor.rs new file mode 100644 index 00000000000..948670380f6 --- /dev/null +++ b/crates/ide-db/src/use_trivial_contructor.rs @@ -0,0 +1,31 @@ +use hir::StructKind; +use syntax::ast; + +pub fn use_trivial_constructor( + db: &crate::RootDatabase, + path: ast::Path, + ty: &hir::Type, +) -> Option { + match ty.as_adt() { + Some(hir::Adt::Enum(x)) => { + if let &[variant] = &*x.variants(db) { + if variant.kind(db) == hir::StructKind::Unit { + let path = ast::make::path_qualified( + path, + syntax::ast::make::path_segment(ast::make::name_ref( + &variant.name(db).to_smol_str(), + )), + ); + + return Some(syntax::ast::make::expr_path(path)); + } + } + } + Some(hir::Adt::Struct(x)) if x.kind(db) == StructKind::Unit => { + return Some(syntax::ast::make::expr_path(path)); + } + _ => {} + } + + None +} From 817082cad6daa9e217f25537ba14e40f1ba874bd Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 22 Jun 2022 16:49:50 +0200 Subject: [PATCH 8/9] add doc strings to use_trivial_contructor.rs --- crates/ide-db/src/use_trivial_contructor.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/ide-db/src/use_trivial_contructor.rs b/crates/ide-db/src/use_trivial_contructor.rs index 948670380f6..39431bed382 100644 --- a/crates/ide-db/src/use_trivial_contructor.rs +++ b/crates/ide-db/src/use_trivial_contructor.rs @@ -1,6 +1,9 @@ +//! Functionality for generating trivial contructors + use hir::StructKind; use syntax::ast; +/// given a type return the trivial contructor (if one exists) pub fn use_trivial_constructor( db: &crate::RootDatabase, path: ast::Path, From a5ad4de11186961f8f9b13cfee383af59e75c5d1 Mon Sep 17 00:00:00 2001 From: soruh Date: Wed, 13 Jul 2022 16:16:48 +0200 Subject: [PATCH 9/9] add tests --- .../ide-assists/src/handlers/generate_new.rs | 91 +++++++++++++++++++ .../src/handlers/missing_fields.rs | 86 ++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs index 4ed241f1af5..5f4715bb53d 100644 --- a/crates/ide-assists/src/handlers/generate_new.rs +++ b/crates/ide-assists/src/handlers/generate_new.rs @@ -123,6 +123,97 @@ mod tests { use super::*; + #[test] + fn test_generate_new_with_zst_fields() { + check_assist( + generate_new, + r#" +struct Empty; + +struct Foo { empty: Empty $0} +"#, + r#" +struct Empty; + +struct Foo { empty: Empty } + +impl Foo { + fn $0new() -> Self { Self { empty: Empty } } +} +"#, + ); + check_assist( + generate_new, + r#" +struct Empty; + +struct Foo { baz: String, empty: Empty $0} +"#, + r#" +struct Empty; + +struct Foo { baz: String, empty: Empty } + +impl Foo { + fn $0new(baz: String) -> Self { Self { baz, empty: Empty } } +} +"#, + ); + check_assist( + generate_new, + r#" +enum Empty { Bar } + +struct Foo { empty: Empty $0} +"#, + r#" +enum Empty { Bar } + +struct Foo { empty: Empty } + +impl Foo { + fn $0new() -> Self { Self { empty: Empty::Bar } } +} +"#, + ); + + // make sure the assist only works on unit variants + check_assist( + generate_new, + r#" +struct Empty {} + +struct Foo { empty: Empty $0} +"#, + r#" +struct Empty {} + +struct Foo { empty: Empty } + +impl Foo { + fn $0new(empty: Empty) -> Self { Self { empty } } +} +"#, + ); + check_assist( + generate_new, + r#" +enum Empty { Bar {} } + +struct Foo { empty: Empty $0} +"#, + r#" +enum Empty { Bar {} } + +struct Foo { empty: Empty } + +impl Foo { + fn $0new(empty: Empty) -> Self { Self { empty } } +} +"#, + ); + } + #[test] fn test_generate_new() { check_assist( diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs index 828d9229821..30f903af50d 100644 --- a/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -345,6 +345,92 @@ fn test_fn() { ); } + #[test] + fn test_fill_struct_zst_fields() { + check_fix( + r#" +struct Empty; + +struct TestStruct { one: i32, two: Empty } + +fn test_fn() { + let s = TestStruct {$0}; +} +"#, + r#" +struct Empty; + +struct TestStruct { one: i32, two: Empty } + +fn test_fn() { + let s = TestStruct { one: 0, two: Empty }; +} +"#, + ); + check_fix( + r#" +enum Empty { Foo }; + +struct TestStruct { one: i32, two: Empty } + +fn test_fn() { + let s = TestStruct {$0}; +} +"#, + r#" +enum Empty { Foo }; + +struct TestStruct { one: i32, two: Empty } + +fn test_fn() { + let s = TestStruct { one: 0, two: Empty::Foo }; +} +"#, + ); + + // make sure the assist doesn't fill non Unit variants + check_fix( + r#" +struct Empty {}; + +struct TestStruct { one: i32, two: Empty } + +fn test_fn() { + let s = TestStruct {$0}; +} +"#, + r#" +struct Empty {}; + +struct TestStruct { one: i32, two: Empty } + +fn test_fn() { + let s = TestStruct { one: 0, two: todo!() }; +} +"#, + ); + check_fix( + r#" +enum Empty { Foo {} }; + +struct TestStruct { one: i32, two: Empty } + +fn test_fn() { + let s = TestStruct {$0}; +} +"#, + r#" +enum Empty { Foo {} }; + +struct TestStruct { one: i32, two: Empty } + +fn test_fn() { + let s = TestStruct { one: 0, two: todo!() }; +} +"#, + ); + } + #[test] fn test_fill_struct_fields_self() { check_fix(