Skip to content

Commit

Permalink
add assist for filling fields by replacing ellipsis in record syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
dfireBird committed Feb 24, 2024
1 parent 03b3cb6 commit 6f4354f
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 0 deletions.
236 changes: 236 additions & 0 deletions crates/ide-assists/src/handlers/fill_record_pattern_fields.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
use syntax::{
ast::{self, make},
AstNode,
};

use crate::{AssistContext, AssistId, Assists};

// Assist: fill_record_pattern_fields
//
// Fills fields by replacing rest pattern in record patterns.
//
// ```
// struct Bar { y: Y, z: Z }
//
// fn foo(bar: Bar) {
// let Bar { ..$0 } = bar;
// }
// ```
// ->
// ```
// struct Bar { y: Y, z: Z }
//
// fn foo(bar: Bar) {
// let Bar { y, z } = bar;
// }
// ```
pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let record_pat = ctx.find_node_at_offset::<ast::RecordPat>()?;

let ellipsis = record_pat.record_pat_field_list().and_then(|r| r.rest_pat())?;
if !ellipsis.syntax().text_range().contains_inclusive(ctx.offset()) {
return None;
}

let target_range = ellipsis.syntax().text_range();

let missing_fields = ctx.sema.record_pattern_missing_fields(&record_pat);

let old_field_list = record_pat.record_pat_field_list()?;
let new_field_list = make::record_pat_field_list(old_field_list.fields()).clone_for_update();
for (f, _) in missing_fields.iter() {
let field =
make::record_pat_field_shorthand(make::name_ref(&f.name(ctx.sema.db).to_smol_str()));
new_field_list.add_field(field.clone_for_update());
}

let old_range = ctx.sema.original_range_opt(old_field_list.syntax())?;
if old_range.file_id != ctx.file_id() {
return None;
}

acc.add(
AssistId("fill_record_pattern_fields", crate::AssistKind::RefactorRewrite),
"Fill structure fields",
target_range,
move |builder| builder.replace_ast(old_field_list, new_field_list),
)
}

#[cfg(test)]
mod tests {
use super::*;
use crate::tests::{check_assist, check_assist_not_applicable};

#[test]
fn fill_fields_enum_with_only_ellipsis() {
check_assist(
fill_record_pattern_fields,
r#"
enum Foo {
A(X),
B{y: Y, z: Z}
}
fn bar(foo: Foo) {
match foo {
Foo::A(_) => false,
Foo::B{ ..$0 } => true,
};
}
"#,
r#"
enum Foo {
A(X),
B{y: Y, z: Z}
}
fn bar(foo: Foo) {
match foo {
Foo::A(_) => false,
Foo::B{ y, z } => true,
};
}
"#,
)
}

#[test]
fn fill_fields_enum_with_fields() {
check_assist(
fill_record_pattern_fields,
r#"
enum Foo {
A(X),
B{y: Y, z: Z}
}
fn bar(foo: Foo) {
match foo {
Foo::A(_) => false,
Foo::B{ y, ..$0 } => true,
};
}
"#,
r#"
enum Foo {
A(X),
B{y: Y, z: Z}
}
fn bar(foo: Foo) {
match foo {
Foo::A(_) => false,
Foo::B{ y, z } => true,
};
}
"#,
)
}

#[test]
fn fill_fields_struct_with_only_ellipsis() {
check_assist(
fill_record_pattern_fields,
r#"
struct Bar {
y: Y,
z: Z,
}
fn foo(bar: Bar) {
let Bar { ..$0 } = bar;
}
"#,
r#"
struct Bar {
y: Y,
z: Z,
}
fn foo(bar: Bar) {
let Bar { y, z } = bar;
}
"#,
)
}

#[test]
fn fill_fields_struct_with_fields() {
check_assist(
fill_record_pattern_fields,
r#"
struct Bar {
y: Y,
z: Z,
}
fn foo(bar: Bar) {
let Bar { y, ..$0 } = bar;
}
"#,
r#"
struct Bar {
y: Y,
z: Z,
}
fn foo(bar: Bar) {
let Bar { y, z } = bar;
}
"#,
)
}

#[test]
fn not_applicable_when_not_in_ellipsis() {
check_assist_not_applicable(
fill_record_pattern_fields,
r#"
enum Foo {
A(X),
B{y: Y, z: Z}
}
fn bar(foo: Foo) {
match foo {
Foo::A(_) => false,
Foo::B{..}$0 => true,
};
}
"#,
);
check_assist_not_applicable(
fill_record_pattern_fields,
r#"
enum Foo {
A(X),
B{y: Y, z: Z}
}
fn bar(foo: Foo) {
match foo {
Foo::A(_) => false,
Foo::B$0{..} => true,
};
}
"#,
);
check_assist_not_applicable(
fill_record_pattern_fields,
r#"
enum Foo {
A(X),
B{y: Y, z: Z}
}
fn bar(foo: Foo) {
match foo {
Foo::A(_) => false,
Foo::$0B{..} => true,
};
}
"#,
);
}
}
2 changes: 2 additions & 0 deletions crates/ide-assists/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ mod handlers {
mod extract_struct_from_enum_variant;
mod extract_type_alias;
mod extract_variable;
mod fill_record_pattern_fields;
mod fix_visibility;
mod flip_binexpr;
mod flip_comma;
Expand Down Expand Up @@ -254,6 +255,7 @@ mod handlers {
extract_expressions_from_format_string::extract_expressions_from_format_string,
extract_struct_from_enum_variant::extract_struct_from_enum_variant,
extract_type_alias::extract_type_alias,
fill_record_pattern_fields::fill_record_pattern_fields,
fix_visibility::fix_visibility,
flip_binexpr::flip_binexpr,
flip_comma::flip_comma,
Expand Down
21 changes: 21 additions & 0 deletions crates/ide-assists/src/tests/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,27 @@ fn main() {
)
}

#[test]
fn doctest_fill_record_pattern_fields() {
check_doc_test(
"fill_record_pattern_fields",
r#####"
struct Bar { y: Y, z: Z }
fn foo(bar: Bar) {
let Bar { ..$0 } = bar;
}
"#####,
r#####"
struct Bar { y: Y, z: Z }
fn foo(bar: Bar) {
let Bar { y, z } = bar;
}
"#####,
)
}

#[test]
fn doctest_fix_visibility() {
check_doc_test(
Expand Down

0 comments on commit 6f4354f

Please sign in to comment.