From 907f7307af8b1824fdd986ff32f78fed5fc54b30 Mon Sep 17 00:00:00 2001 From: yanchith Date: Sun, 17 Mar 2019 19:48:25 +0100 Subject: Implement naive version of fill_struct_fields assist --- crates/ra_assists/src/fill_struct_fields.rs | 120 ++++++++++++++++++++++++++++ crates/ra_assists/src/lib.rs | 2 + 2 files changed, 122 insertions(+) create mode 100644 crates/ra_assists/src/fill_struct_fields.rs (limited to 'crates') diff --git a/crates/ra_assists/src/fill_struct_fields.rs b/crates/ra_assists/src/fill_struct_fields.rs new file mode 100644 index 000000000..05a5ebf66 --- /dev/null +++ b/crates/ra_assists/src/fill_struct_fields.rs @@ -0,0 +1,120 @@ +use std::fmt::Write; + +use hir::{AdtDef, Ty, source_binder}; +use hir::db::HirDatabase; + +use ra_syntax::ast::{self, AstNode, Expr}; + +use crate::{AssistCtx, Assist, AssistId}; + +pub(crate) fn fill_struct_fields(mut ctx: AssistCtx) -> Option { + let struct_lit = ctx.node_at_offset::()?; + + // If we already have existing struct fields, don't provide the assist. + // TODO: provide assist for tuple structs + match struct_lit.named_field_list() { + Some(named_field_list) if named_field_list.fields().count() > 0 => { + return None; + } + _ => {} + } + + let expr: &Expr = struct_lit.into(); + let function = + source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, struct_lit.syntax())?; + + let infer_result = function.infer(ctx.db); + let source_map = function.body_source_map(ctx.db); + let node_expr = source_map.node_expr(expr)?; + let struct_lit_ty = infer_result[node_expr].clone(); + let struct_def = match struct_lit_ty { + Ty::Adt { def_id: AdtDef::Struct(s), .. } => s, + _ => return None, + }; + + let struct_name = struct_def.name(ctx.db)?; + let db = ctx.db; + + ctx.add_action(AssistId("fill_struct_fields"), "fill struct fields", |edit| { + let mut buf = format!("{} {{\n", struct_name); + let struct_fields = struct_def.fields(db); + for field in struct_fields { + let field_name = field.name(db).to_string(); + write!(&mut buf, " {}: (),\n", field_name).unwrap(); + } + buf.push_str("}"); + + edit.target(struct_lit.syntax().range()); + edit.set_cursor(expr.syntax().range().start()); + edit.replace_node_and_indent(struct_lit.syntax(), buf); + }); + + ctx.build() +} + +#[cfg(test)] +mod tests { + use crate::helpers::{check_assist, check_assist_target}; + + use super::fill_struct_fields; + + #[test] + fn fill_struct_fields_empty_body() { + check_assist( + fill_struct_fields, + r#" + struct S<'a, D> { + a: u32, + b: String, + c: (i32, i32), + d: D, + r: &'a str, + } + + fn main() { + let s = S<|> {} + } + "#, + r#" + struct S<'a, D> { + a: u32, + b: String, + c: (i32, i32), + d: D, + r: &'a str, + } + + fn main() { + let s = <|>S { + a: (), + b: (), + c: (), + d: (), + r: (), + } + } + "#, + ); + } + + #[test] + fn fill_struct_fields_target() { + check_assist_target( + fill_struct_fields, + r#" + struct S<'a, D> { + a: u32, + b: String, + c: (i32, i32), + d: D, + r: &'a str, + } + + fn main() { + let s = S<|> {} + } + "#, + "S {}", + ); + } +} diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 6c3d75d79..5efc5025e 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs @@ -90,6 +90,7 @@ mod add_impl; mod flip_comma; mod change_visibility; mod fill_match_arms; +mod fill_struct_fields; mod introduce_variable; mod replace_if_let_with_match; mod split_import; @@ -102,6 +103,7 @@ fn all_assists() -> &'static [fn(AssistCtx) -> Option Date: Mon, 18 Mar 2019 08:19:51 +0100 Subject: Remove unachievable TODO --- crates/ra_assists/src/fill_struct_fields.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'crates') diff --git a/crates/ra_assists/src/fill_struct_fields.rs b/crates/ra_assists/src/fill_struct_fields.rs index 05a5ebf66..938322d1d 100644 --- a/crates/ra_assists/src/fill_struct_fields.rs +++ b/crates/ra_assists/src/fill_struct_fields.rs @@ -11,7 +11,6 @@ pub(crate) fn fill_struct_fields(mut ctx: AssistCtx) -> Option let struct_lit = ctx.node_at_offset::()?; // If we already have existing struct fields, don't provide the assist. - // TODO: provide assist for tuple structs match struct_lit.named_field_list() { Some(named_field_list) if named_field_list.fields().count() > 0 => { return None; -- cgit v1.2.3 From ca262fbab80dd74fd585544b9e6ce99e394dc573 Mon Sep 17 00:00:00 2001 From: yanchith Date: Mon, 18 Mar 2019 09:03:10 +0100 Subject: Only replace NamedFieldList and add test for preserving Self --- crates/ra_assists/src/fill_struct_fields.rs | 58 ++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 13 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/fill_struct_fields.rs b/crates/ra_assists/src/fill_struct_fields.rs index 938322d1d..90ce9c577 100644 --- a/crates/ra_assists/src/fill_struct_fields.rs +++ b/crates/ra_assists/src/fill_struct_fields.rs @@ -3,39 +3,34 @@ use std::fmt::Write; use hir::{AdtDef, Ty, source_binder}; use hir::db::HirDatabase; -use ra_syntax::ast::{self, AstNode, Expr}; +use ra_syntax::ast::{self, AstNode}; use crate::{AssistCtx, Assist, AssistId}; pub(crate) fn fill_struct_fields(mut ctx: AssistCtx) -> Option { let struct_lit = ctx.node_at_offset::()?; + let named_field_list = struct_lit.named_field_list()?; // If we already have existing struct fields, don't provide the assist. - match struct_lit.named_field_list() { - Some(named_field_list) if named_field_list.fields().count() > 0 => { - return None; - } - _ => {} + if named_field_list.fields().count() > 0 { + return None; } - let expr: &Expr = struct_lit.into(); let function = source_binder::function_from_child_node(ctx.db, ctx.frange.file_id, struct_lit.syntax())?; let infer_result = function.infer(ctx.db); let source_map = function.body_source_map(ctx.db); - let node_expr = source_map.node_expr(expr)?; + let node_expr = source_map.node_expr(struct_lit.into())?; let struct_lit_ty = infer_result[node_expr].clone(); let struct_def = match struct_lit_ty { Ty::Adt { def_id: AdtDef::Struct(s), .. } => s, _ => return None, }; - let struct_name = struct_def.name(ctx.db)?; let db = ctx.db; - ctx.add_action(AssistId("fill_struct_fields"), "fill struct fields", |edit| { - let mut buf = format!("{} {{\n", struct_name); + let mut buf = String::from("{\n"); let struct_fields = struct_def.fields(db); for field in struct_fields { let field_name = field.name(db).to_string(); @@ -44,8 +39,8 @@ pub(crate) fn fill_struct_fields(mut ctx: AssistCtx) -> Option buf.push_str("}"); edit.target(struct_lit.syntax().range()); - edit.set_cursor(expr.syntax().range().start()); - edit.replace_node_and_indent(struct_lit.syntax(), buf); + edit.set_cursor(struct_lit.syntax().range().start()); + edit.replace_node_and_indent(named_field_list.syntax(), buf); }); ctx.build() @@ -116,4 +111,41 @@ mod tests { "S {}", ); } + + #[test] + fn fill_struct_fields_preserve_self() { + check_assist( + fill_struct_fields, + r#" + struct Foo { + foo: u8, + bar: String, + baz: i128, + } + + impl Foo { + pub fn new() -> Self { + Self <|>{} + } + } + "#, + r#" + struct Foo { + foo: u8, + bar: String, + baz: i128, + } + + impl Foo { + pub fn new() -> Self { + <|>Self { + foo: (), + bar: (), + baz: (), + } + } + } + "#, + ); + } } -- cgit v1.2.3