diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 55448d4ae868..7549d54a544e 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -296,6 +296,7 @@ pub enum ModuleDef { Function(Function), Adt(Adt), // Can't be directly declared, but can be imported. + // FIXME: Rename to `EnumVariant` Variant(Variant), Const(Const), Static(Static), @@ -1564,6 +1565,7 @@ impl From<&Variant> for DefWithBodyId { } } +// FIXME: Rename to `EnumVariant` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Variant { pub(crate) id: EnumVariantId, diff --git a/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs b/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs similarity index 87% rename from crates/ide-assists/src/handlers/explicit_enum_discriminant.rs rename to crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs index fafc3448a87c..1a5de9cb071b 100644 --- a/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs +++ b/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs @@ -8,7 +8,7 @@ use syntax::{ast, AstNode}; use crate::{AssistContext, Assists}; -// Assist: explicit_enum_discriminant +// Assist: add_explicit_enum_discriminant // // Adds explicit discriminant to all enum variants. // @@ -29,7 +29,10 @@ use crate::{AssistContext, Assists}; // Quux = 43, // } // ``` -pub(crate) fn explicit_enum_discriminant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { +pub(crate) fn add_explicit_enum_discriminant( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { let enum_node = ctx.find_node_at_offset::()?; let enum_def = ctx.sema.to_def(&enum_node)?; @@ -50,7 +53,7 @@ pub(crate) fn explicit_enum_discriminant(acc: &mut Assists, ctx: &AssistContext< } acc.add( - AssistId("explicit_enum_discriminant", AssistKind::RefactorRewrite), + AssistId("add_explicit_enum_discriminant", AssistKind::RefactorRewrite), "Add explicit enum discriminants", enum_node.syntax().text_range(), |builder| { @@ -88,12 +91,12 @@ fn add_variant_discriminant( mod tests { use crate::tests::{check_assist, check_assist_not_applicable}; - use super::explicit_enum_discriminant; + use super::add_explicit_enum_discriminant; #[test] fn non_primitive_repr_non_data_bearing_add_discriminant() { check_assist( - explicit_enum_discriminant, + add_explicit_enum_discriminant, r#" enum TheEnum$0 { Foo, @@ -120,7 +123,7 @@ enum TheEnum { #[test] fn primitive_repr_data_bearing_add_discriminant() { check_assist( - explicit_enum_discriminant, + add_explicit_enum_discriminant, r#" #[repr(u8)] $0enum TheEnum { @@ -145,7 +148,7 @@ enum TheEnum { #[test] fn non_primitive_repr_data_bearing_not_applicable() { check_assist_not_applicable( - explicit_enum_discriminant, + add_explicit_enum_discriminant, r#" enum TheEnum$0 { Foo, @@ -159,7 +162,7 @@ enum TheEnum$0 { #[test] fn primitive_repr_non_data_bearing_add_discriminant() { check_assist( - explicit_enum_discriminant, + add_explicit_enum_discriminant, r#" #[repr(i64)] enum TheEnum { @@ -184,7 +187,7 @@ enum TheEnum { #[test] fn discriminants_already_explicit_not_applicable() { check_assist_not_applicable( - explicit_enum_discriminant, + add_explicit_enum_discriminant, r#" enum TheEnum$0 { Foo = 0, @@ -197,7 +200,7 @@ enum TheEnum$0 { #[test] fn empty_enum_not_applicable() { check_assist_not_applicable( - explicit_enum_discriminant, + add_explicit_enum_discriminant, r#" enum TheEnum$0 {} "#, diff --git a/crates/ide-assists/src/handlers/bool_to_enum.rs b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs similarity index 95% rename from crates/ide-assists/src/handlers/bool_to_enum.rs rename to crates/ide-assists/src/handlers/convert_bool_to_enum.rs index cbd39796241b..7716e99e604b 100644 --- a/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/crates/ide-assists/src/handlers/convert_bool_to_enum.rs @@ -26,7 +26,7 @@ use crate::{ utils, }; -// Assist: bool_to_enum +// Assist: convert_bool_to_enum // // This converts boolean local variables, fields, constants, and statics into a new // enum with two variants `Bool::True` and `Bool::False`, as well as replacing @@ -55,14 +55,14 @@ use crate::{ // } // } // ``` -pub(crate) fn bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { +pub(crate) fn convert_bool_to_enum(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let BoolNodeData { target_node, name, ty_annotation, initializer, definition } = find_bool_node(ctx)?; let target_module = ctx.sema.scope(&target_node)?.module().nearest_non_block_module(ctx.db()); let target = name.syntax().text_range(); acc.add( - AssistId("bool_to_enum", AssistKind::RefactorRewrite), + AssistId("convert_bool_to_enum", AssistKind::RefactorRewrite), "Convert boolean to enum", target, |edit| { @@ -549,7 +549,7 @@ mod tests { #[test] fn parameter_with_first_param_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn function($0foo: bool, bar: bool) { if foo { @@ -573,7 +573,7 @@ fn function(foo: Bool, bar: bool) { #[test] fn no_duplicate_enums() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" #[derive(PartialEq, Eq)] enum Bool { True, False } @@ -600,7 +600,7 @@ fn function(foo: bool, bar: Bool) { #[test] fn parameter_with_last_param_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn function(foo: bool, $0bar: bool) { if bar { @@ -624,7 +624,7 @@ fn function(foo: bool, bar: Bool) { #[test] fn parameter_with_middle_param_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn function(foo: bool, $0bar: bool, baz: bool) { if bar { @@ -648,7 +648,7 @@ fn function(foo: bool, bar: Bool, baz: bool) { #[test] fn parameter_with_closure_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let foo = |$0bar: bool| bar; @@ -668,7 +668,7 @@ fn main() { #[test] fn local_variable_with_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo = true; @@ -697,7 +697,7 @@ fn main() { fn local_variable_with_usage_negated() { cov_mark::check!(replaces_negation); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo = true; @@ -726,7 +726,7 @@ fn main() { fn local_variable_with_type_annotation() { cov_mark::check!(replaces_ty_annotation); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo: bool = false; @@ -746,7 +746,7 @@ fn main() { #[test] fn local_variable_with_non_literal_initializer() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo = 1 == 2; @@ -766,7 +766,7 @@ fn main() { #[test] fn local_variable_binexpr_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo = false; @@ -796,7 +796,7 @@ fn main() { #[test] fn local_variable_unop_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo = true; @@ -825,7 +825,7 @@ fn main() { fn local_variable_assigned_later() { cov_mark::check!(replaces_assignment); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo: bool; @@ -847,7 +847,7 @@ fn main() { #[test] fn local_variable_does_not_apply_recursively() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo = true; @@ -878,7 +878,7 @@ fn main() { fn local_variable_nested_in_negation() { cov_mark::check!(dont_overwrite_expression_inside_negation); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { if !"foo".chars().any(|c| { @@ -909,7 +909,7 @@ fn main() { fn local_variable_non_bool() { cov_mark::check!(not_applicable_non_bool_local); check_assist_not_applicable( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let $0foo = 1; @@ -921,7 +921,7 @@ fn main() { #[test] fn local_variable_cursor_not_on_ident() { check_assist_not_applicable( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let foo = $0true; @@ -933,7 +933,7 @@ fn main() { #[test] fn local_variable_non_ident_pat() { check_assist_not_applicable( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { let ($0foo, bar) = (true, false); @@ -945,7 +945,7 @@ fn main() { #[test] fn local_var_init_struct_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Foo { foo: bool, @@ -975,7 +975,7 @@ fn main() { #[test] fn local_var_init_struct_usage_in_macro() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Struct { boolean: bool, @@ -1018,7 +1018,7 @@ fn new() -> Struct { fn field_struct_basic() { cov_mark::check!(replaces_record_expr); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Foo { $0bar: bool, @@ -1057,7 +1057,7 @@ fn main() { fn field_enum_basic() { cov_mark::check!(replaces_record_pat); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" enum Foo { Foo, @@ -1100,7 +1100,7 @@ fn main() { fn field_enum_cross_file() { // FIXME: The import is missing check_assist( - bool_to_enum, + convert_bool_to_enum, r#" //- /foo.rs pub enum Foo { @@ -1151,7 +1151,7 @@ fn main() { fn field_enum_shorthand() { cov_mark::check!(replaces_record_pat_shorthand); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" enum Foo { Foo, @@ -1200,7 +1200,7 @@ fn main() { fn field_enum_replaces_literal_patterns() { cov_mark::check!(replaces_literal_pat); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" enum Foo { Foo, @@ -1238,7 +1238,7 @@ fn main() { #[test] fn field_enum_keeps_wildcard_patterns() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" enum Foo { Foo, @@ -1276,7 +1276,7 @@ fn main() { #[test] fn field_union_basic() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" union Foo { $0foo: bool, @@ -1314,7 +1314,7 @@ fn main() { #[test] fn field_negated() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Foo { $0bar: bool, @@ -1350,7 +1350,7 @@ fn main() { #[test] fn field_in_mod_properly_indented() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" mod foo { struct Bar { @@ -1386,7 +1386,7 @@ mod foo { #[test] fn field_multiple_initializations() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Foo { $0bar: bool, @@ -1427,7 +1427,7 @@ fn main() { fn field_assigned_to_another() { cov_mark::check!(dont_assign_incorrect_ref); check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Foo { $0foo: bool, @@ -1469,7 +1469,7 @@ fn main() { #[test] fn field_initialized_with_other() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Foo { $0foo: bool, @@ -1507,7 +1507,7 @@ fn main() { #[test] fn field_method_chain_usage() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Foo { $0bool: bool, @@ -1539,7 +1539,7 @@ fn main() { #[test] fn field_in_macro() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" struct Struct { $0boolean: bool, @@ -1580,7 +1580,7 @@ fn new() -> Struct { fn field_non_bool() { cov_mark::check!(not_applicable_non_bool_field); check_assist_not_applicable( - bool_to_enum, + convert_bool_to_enum, r#" struct Foo { $0bar: usize, @@ -1596,7 +1596,7 @@ fn main() { #[test] fn const_basic() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" const $0FOO: bool = false; @@ -1624,7 +1624,7 @@ fn main() { #[test] fn const_in_module() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { if foo::FOO { @@ -1658,7 +1658,7 @@ mod foo { #[test] fn const_in_module_with_import() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" fn main() { use foo::FOO; @@ -1696,7 +1696,7 @@ mod foo { #[test] fn const_cross_file() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" //- /main.rs mod foo; @@ -1734,7 +1734,7 @@ pub const FOO: Bool = Bool::True; #[test] fn const_cross_file_and_module() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" //- /main.rs mod foo; @@ -1780,7 +1780,7 @@ pub mod bar { #[test] fn const_in_impl_cross_file() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" //- /main.rs mod foo; @@ -1824,7 +1824,7 @@ fn foo() -> bool { #[test] fn const_in_trait() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" trait Foo { const $0BOOL: bool; @@ -1865,7 +1865,7 @@ fn main() { fn const_non_bool() { cov_mark::check!(not_applicable_non_bool_const); check_assist_not_applicable( - bool_to_enum, + convert_bool_to_enum, r#" const $0FOO: &str = "foo"; @@ -1879,7 +1879,7 @@ fn main() { #[test] fn static_basic() { check_assist( - bool_to_enum, + convert_bool_to_enum, r#" static mut $0BOOL: bool = true; @@ -1910,7 +1910,7 @@ fn main() { fn static_non_bool() { cov_mark::check!(not_applicable_non_bool_static); check_assist_not_applicable( - bool_to_enum, + convert_bool_to_enum, r#" static mut $0FOO: usize = 0; @@ -1925,6 +1925,6 @@ fn main() { #[test] fn not_applicable_to_other_names() { - check_assist_not_applicable(bool_to_enum, "fn $0main() {}") + check_assist_not_applicable(convert_bool_to_enum, "fn $0main() {}") } } diff --git a/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs b/crates/ide-assists/src/handlers/expand_rest_pattern.rs similarity index 52% rename from crates/ide-assists/src/handlers/fill_record_pattern_fields.rs rename to crates/ide-assists/src/handlers/expand_rest_pattern.rs index ee321864805e..c79a982c38d0 100644 --- a/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs +++ b/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -1,11 +1,29 @@ +use hir::{PathResolution, StructKind}; +use ide_db::syntax_helpers::suggest_name::NameGenerator; use syntax::{ ast::{self, make}, - AstNode, ToSmolStr, + match_ast, AstNode, ToSmolStr, }; use crate::{AssistContext, AssistId, Assists}; -// Assist: fill_record_pattern_fields +pub(crate) fn expand_rest_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let rest_pat = ctx.find_node_at_offset::()?; + let parent = rest_pat.syntax().parent()?; + match_ast! { + match parent { + ast::RecordPatFieldList(it) => expand_record_rest_pattern(acc, ctx, it.syntax().parent().and_then(ast::RecordPat::cast)?, rest_pat), + ast::TupleStructPat(it) => expand_tuple_struct_rest_pattern(acc, ctx, it, rest_pat), + // FIXME + // ast::TuplePat(it) => (), + // FIXME + // ast::SlicePat(it) => (), + _ => return None, + } + } +} + +// Assist: expand_record_rest_pattern // // Fills fields by replacing rest pattern in record patterns. // @@ -24,16 +42,12 @@ use crate::{AssistContext, AssistId, Assists}; // 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::()?; - - 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(); - +fn expand_record_rest_pattern( + acc: &mut Assists, + ctx: &AssistContext<'_>, + record_pat: ast::RecordPat, + rest_pat: ast::RestPat, +) -> Option<()> { let missing_fields = ctx.sema.record_pattern_missing_fields(&record_pat); if missing_fields.is_empty() { @@ -42,6 +56,11 @@ pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext< } let old_field_list = record_pat.record_pat_field_list()?; + let old_range = ctx.sema.original_range_opt(old_field_list.syntax())?; + if old_range.file_id != ctx.file_id() { + return None; + } + let new_field_list = make::record_pat_field_list(old_field_list.fields(), None).clone_for_update(); for (f, _) in missing_fields.iter() { @@ -52,16 +71,93 @@ pub(crate) fn fill_record_pattern_fields(acc: &mut Assists, ctx: &AssistContext< new_field_list.add_field(field.clone_for_update()); } - let old_range = ctx.sema.original_range_opt(old_field_list.syntax())?; + let target_range = rest_pat.syntax().text_range(); + acc.add( + AssistId("expand_record_rest_pattern", crate::AssistKind::RefactorRewrite), + "Fill struct fields", + target_range, + move |builder| builder.replace_ast(old_field_list, new_field_list), + ) +} +// Assist: expand_tuple_struct_rest_pattern +// +// Fills fields by replacing rest pattern in tuple struct patterns. +// +// ``` +// struct Bar(Y, Z); +// +// fn foo(bar: Bar) { +// let Bar(..$0) = bar; +// } +// ``` +// -> +// ``` +// struct Bar(Y, Z); +// +// fn foo(bar: Bar) { +// let Bar(_0, _1) = bar; +// } +// ``` +fn expand_tuple_struct_rest_pattern( + acc: &mut Assists, + ctx: &AssistContext<'_>, + pat: ast::TupleStructPat, + rest_pat: ast::RestPat, +) -> Option<()> { + let path = pat.path()?; + let fields = match ctx.sema.type_of_pat(&pat.clone().into())?.original.as_adt()? { + hir::Adt::Struct(s) if s.kind(ctx.sema.db) == StructKind::Tuple => s.fields(ctx.sema.db), + hir::Adt::Enum(_) => match ctx.sema.resolve_path(&path)? { + PathResolution::Def(hir::ModuleDef::Variant(v)) + if v.kind(ctx.sema.db) == StructKind::Tuple => + { + v.fields(ctx.sema.db) + } + _ => return None, + }, + _ => return None, + }; + + let rest_pat = rest_pat.into(); + let mut pats = pat.fields(); + let prefix_count = pats.by_ref().position(|p| p == rest_pat)?; + let suffix_count = pats.count(); + + if fields.len().saturating_sub(prefix_count).saturating_sub(suffix_count) == 0 { + cov_mark::hit!(no_missing_fields_tuple_struct); + return None; + } + + let old_range = ctx.sema.original_range_opt(pat.syntax())?; if old_range.file_id != ctx.file_id() { return None; } + let mut name_gen = NameGenerator::new_from_scope_locals(ctx.sema.scope(pat.syntax())); + let new_pat = make::tuple_struct_pat( + path, + pat.fields() + .take(prefix_count) + .chain(fields[prefix_count..fields.len() - suffix_count].iter().map(|f| { + make::ident_pat( + false, + false, + match name_gen.for_type(&f.ty(ctx.sema.db), ctx.sema.db, ctx.edition()) { + Some(name) => make::name(&name), + None => make::name(&format!("_{}", f.index())), + }, + ) + .into() + })) + .chain(pat.fields().skip(prefix_count + 1)), + ); + + let target_range = rest_pat.syntax().text_range(); acc.add( - AssistId("fill_record_pattern_fields", crate::AssistKind::RefactorRewrite), - "Fill structure fields", + AssistId("expand_tuple_struct_rest_pattern", crate::AssistKind::RefactorRewrite), + "Fill tuple struct fields", target_range, - move |builder| builder.replace_ast(old_field_list, new_field_list), + move |builder| builder.replace_ast(pat, new_pat), ) } @@ -73,7 +169,7 @@ mod tests { #[test] fn fill_fields_enum_with_only_ellipsis() { check_assist( - fill_record_pattern_fields, + expand_rest_pattern, r#" enum Foo { A(X), @@ -106,7 +202,7 @@ fn bar(foo: Foo) { #[test] fn fill_fields_enum_with_fields() { check_assist( - fill_record_pattern_fields, + expand_rest_pattern, r#" enum Foo { A(X), @@ -139,7 +235,7 @@ fn bar(foo: Foo) { #[test] fn fill_fields_struct_with_only_ellipsis() { check_assist( - fill_record_pattern_fields, + expand_rest_pattern, r#" struct Bar { y: Y, @@ -159,6 +255,27 @@ struct Bar { fn foo(bar: Bar) { let Bar { y, z } = bar; } +"#, + ); + check_assist( + expand_rest_pattern, + r#" +struct Y; +struct Z; +struct Bar(Y, Z) + +fn foo(bar: Bar) { + let Bar(..$0) = bar; +} +"#, + r#" +struct Y; +struct Z; +struct Bar(Y, Z) + +fn foo(bar: Bar) { + let Bar(y, z) = bar; +} "#, ) } @@ -166,7 +283,7 @@ fn foo(bar: Bar) { #[test] fn fill_fields_struct_with_fields() { check_assist( - fill_record_pattern_fields, + expand_rest_pattern, r#" struct Bar { y: Y, @@ -186,6 +303,29 @@ struct Bar { fn foo(bar: Bar) { let Bar { y, z } = bar; } +"#, + ); + check_assist( + expand_rest_pattern, + r#" +struct X; +struct Y; +struct Z; +struct Bar(X, Y, Z) + +fn foo(bar: Bar) { + let Bar(x, ..$0, z) = bar; +} +"#, + r#" +struct X; +struct Y; +struct Z; +struct Bar(X, Y, Z) + +fn foo(bar: Bar) { + let Bar(x, y, z) = bar; +} "#, ) } @@ -193,7 +333,7 @@ fn foo(bar: Bar) { #[test] fn fill_fields_struct_generated_by_macro() { check_assist( - fill_record_pattern_fields, + expand_rest_pattern, r#" macro_rules! position { ($t: ty) => { @@ -226,7 +366,7 @@ fn macro_call(pos: Pos) { #[test] fn fill_fields_enum_generated_by_macro() { check_assist( - fill_record_pattern_fields, + expand_rest_pattern, r#" macro_rules! enum_gen { ($t: ty) => { @@ -271,7 +411,7 @@ fn macro_call(foo: Foo) { #[test] fn not_applicable_when_not_in_ellipsis() { check_assist_not_applicable( - fill_record_pattern_fields, + expand_rest_pattern, r#" enum Foo { A(X), @@ -287,7 +427,7 @@ fn bar(foo: Foo) { "#, ); check_assist_not_applicable( - fill_record_pattern_fields, + expand_rest_pattern, r#" enum Foo { A(X), @@ -303,7 +443,7 @@ fn bar(foo: Foo) { "#, ); check_assist_not_applicable( - fill_record_pattern_fields, + expand_rest_pattern, r#" enum Foo { A(X), @@ -324,8 +464,9 @@ fn bar(foo: Foo) { fn not_applicable_when_no_missing_fields() { // This is still possible even though it's meaningless cov_mark::check!(no_missing_fields); + cov_mark::check!(no_missing_fields_tuple_struct); check_assist_not_applicable( - fill_record_pattern_fields, + expand_rest_pattern, r#" enum Foo { A(X), @@ -341,7 +482,7 @@ fn bar(foo: Foo) { "#, ); check_assist_not_applicable( - fill_record_pattern_fields, + expand_rest_pattern, r#" struct Bar { y: Y, @@ -351,6 +492,16 @@ struct Bar { fn foo(bar: Bar) { let Bar { y, z, ..$0 } = bar; } +"#, + ); + check_assist_not_applicable( + expand_rest_pattern, + r#" +struct Bar(Y, Z) + +fn foo(bar: Bar) { + let Bar(y, ..$0, z) = bar; +} "#, ); } diff --git a/crates/ide-assists/src/handlers/introduce_named_generic.rs b/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs similarity index 84% rename from crates/ide-assists/src/handlers/introduce_named_generic.rs rename to crates/ide-assists/src/handlers/introduce_named_type_parameter.rs index 8c276415bb1f..994e4a0eddaf 100644 --- a/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs @@ -4,7 +4,7 @@ use syntax::ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams use crate::{AssistContext, AssistId, AssistKind, Assists}; -// Assist: introduce_named_generic +// Assist: introduce_named_type_parameter // // Replaces `impl Trait` function argument with the named generic. // @@ -15,18 +15,20 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` // fn foo<$0B: Bar>(bar: B) {} // ``` -pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { +pub(crate) fn introduce_named_type_parameter( + acc: &mut Assists, + ctx: &AssistContext<'_>, +) -> Option<()> { let impl_trait_type = ctx.find_node_at_offset::()?; let param = impl_trait_type.syntax().ancestors().find_map(ast::Param::cast)?; - let fn_ = param.syntax().ancestors().find_map(ast::Fn::cast)?; - + let fn_ = param.syntax().ancestors().nth(2).and_then(ast::Fn::cast)?; let type_bound_list = impl_trait_type.type_bound_list()?; let make = SyntaxFactory::new(); let target = fn_.syntax().text_range(); acc.add( - AssistId("introduce_named_generic", AssistKind::RefactorRewrite), - "Replace impl trait with generic", + AssistId("introduce_named_type_parameter", AssistKind::RefactorRewrite), + "Replace impl trait with type parameter", target, |builder| { let mut editor = builder.make_editor(fn_.syntax()); @@ -71,7 +73,7 @@ mod tests { #[test] fn introduce_named_generic_params() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn foo(bar: $0impl Bar) {}"#, r#"fn foo(bar: B) {}"#, ); @@ -80,7 +82,7 @@ mod tests { #[test] fn replace_impl_trait_without_generic_params() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn foo(bar: $0impl Bar) {}"#, r#"fn foo<$0B: Bar>(bar: B) {}"#, ); @@ -89,7 +91,7 @@ mod tests { #[test] fn replace_two_impl_trait_with_generic_params() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn foo(foo: impl Foo, bar: $0impl Bar) {}"#, r#"fn foo(foo: impl Foo, bar: B) {}"#, ); @@ -98,7 +100,7 @@ mod tests { #[test] fn replace_impl_trait_with_empty_generic_params() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn foo<>(bar: $0impl Bar) {}"#, r#"fn foo<$0B: Bar>(bar: B) {}"#, ); @@ -107,7 +109,7 @@ mod tests { #[test] fn replace_impl_trait_with_empty_multiline_generic_params() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#" fn foo< >(bar: $0impl Bar) {} @@ -122,7 +124,7 @@ fn foo<$0B: Bar #[test] fn replace_impl_trait_with_exist_generic_letter() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn foo(bar: $0impl Bar) {}"#, r#"fn foo(bar: B1) {}"#, ); @@ -131,7 +133,7 @@ fn foo<$0B: Bar #[test] fn replace_impl_trait_with_more_exist_generic_letter() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn foo(bar: $0impl Bar) {}"#, r#"fn foo(bar: B4) {}"#, ); @@ -140,7 +142,7 @@ fn foo<$0B: Bar #[test] fn replace_impl_trait_with_multiline_generic_params() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#" fn foo< G: Foo, @@ -161,7 +163,7 @@ fn foo< #[test] fn replace_impl_trait_multiple() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn foo(bar: $0impl Foo + Bar) {}"#, r#"fn foo<$0F: Foo + Bar>(bar: F) {}"#, ); @@ -170,7 +172,7 @@ fn foo< #[test] fn replace_impl_with_mut() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn f(iter: &mut $0impl Iterator) {}"#, r#"fn f<$0I: Iterator>(iter: &mut I) {}"#, ); @@ -179,7 +181,7 @@ fn foo< #[test] fn replace_impl_inside() { check_assist( - introduce_named_generic, + introduce_named_type_parameter, r#"fn f(x: &mut Vec<$0impl Iterator>) {}"#, r#"fn f<$0I: Iterator>(x: &mut Vec) {}"#, ); diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs index 448bcadb8ef2..e8480b0de190 100644 --- a/crates/ide-assists/src/lib.rs +++ b/crates/ide-assists/src/lib.rs @@ -105,6 +105,7 @@ mod handlers { pub(crate) type Handler = fn(&mut Assists, &AssistContext<'_>) -> Option<()>; mod add_braces; + mod add_explicit_enum_discriminant; mod add_explicit_type; mod add_label_to_loop; mod add_lifetime_to_type; @@ -115,9 +116,9 @@ mod handlers { mod apply_demorgan; mod auto_import; mod bind_unused_param; - mod bool_to_enum; mod change_visibility; mod convert_bool_then; + mod convert_bool_to_enum; mod convert_closure_to_fn; mod convert_comment_block; mod convert_comment_from_or_to_doc; @@ -138,14 +139,13 @@ mod handlers { mod destructure_tuple_binding; mod desugar_doc_comment; mod expand_glob_import; - mod explicit_enum_discriminant; + mod expand_rest_pattern; mod extract_expressions_from_format_string; mod extract_function; mod extract_module; 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; @@ -177,8 +177,8 @@ mod handlers { mod inline_macro; mod inline_type_alias; mod into_to_qualified_from; - mod introduce_named_generic; mod introduce_named_lifetime; + mod introduce_named_type_parameter; mod invert_if; mod merge_imports; mod merge_match_arms; @@ -234,49 +234,47 @@ mod handlers { &[ // These are alphabetic for the foolish consistency add_braces::add_braces, + add_explicit_enum_discriminant::add_explicit_enum_discriminant, add_explicit_type::add_explicit_type, add_label_to_loop::add_label_to_loop, - add_missing_match_arms::add_missing_match_arms, add_lifetime_to_type::add_lifetime_to_type, + add_missing_match_arms::add_missing_match_arms, add_return_type::add_return_type, add_turbo_fish::add_turbo_fish, - apply_demorgan::apply_demorgan, apply_demorgan::apply_demorgan_iterator, + apply_demorgan::apply_demorgan, auto_import::auto_import, bind_unused_param::bind_unused_param, - bool_to_enum::bool_to_enum, change_visibility::change_visibility, convert_bool_then::convert_bool_then_to_if, convert_bool_then::convert_if_to_bool_then, - toggle_async_sugar::desugar_async_into_impl_future, - toggle_async_sugar::sugar_impl_future_into_async, + convert_bool_to_enum::convert_bool_to_enum, + convert_closure_to_fn::convert_closure_to_fn, convert_comment_block::convert_comment_block, convert_comment_from_or_to_doc::convert_comment_from_or_to_doc, - convert_closure_to_fn::convert_closure_to_fn, convert_from_to_tryfrom::convert_from_to_tryfrom, convert_integer_literal::convert_integer_literal, convert_into_to_from::convert_into_to_from, - convert_iter_for_each_to_for::convert_iter_for_each_to_for, convert_iter_for_each_to_for::convert_for_loop_with_for_each, + convert_iter_for_each_to_for::convert_iter_for_each_to_for, convert_let_else_to_match::convert_let_else_to_match, convert_match_to_let_else::convert_match_to_let_else, - convert_tuple_return_type_to_struct::convert_tuple_return_type_to_struct, convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct, convert_nested_function_to_closure::convert_nested_function_to_closure, convert_to_guarded_return::convert_to_guarded_return, + convert_tuple_return_type_to_struct::convert_tuple_return_type_to_struct, convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct, convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro, convert_while_to_loop::convert_while_to_loop, - desugar_doc_comment::desugar_doc_comment, - destructure_tuple_binding::destructure_tuple_binding, destructure_struct_binding::destructure_struct_binding, + destructure_tuple_binding::destructure_tuple_binding, + desugar_doc_comment::desugar_doc_comment, expand_glob_import::expand_glob_import, expand_glob_import::expand_glob_reexport, - explicit_enum_discriminant::explicit_enum_discriminant, + expand_rest_pattern::expand_rest_pattern, 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, @@ -287,8 +285,8 @@ mod handlers { generate_default_from_new::generate_default_from_new, generate_delegate_trait::generate_delegate_trait, generate_derive::generate_derive, - generate_documentation_template::generate_documentation_template, generate_documentation_template::generate_doc_example, + generate_documentation_template::generate_documentation_template, generate_enum_is_method::generate_enum_is_method, generate_enum_projection_method::generate_enum_as_method, generate_enum_projection_method::generate_enum_try_into_method, @@ -298,8 +296,8 @@ mod handlers { generate_function::generate_function, generate_impl::generate_impl, generate_impl::generate_trait_impl, - generate_mut_trait_impl::generate_mut_trait_impl, generate_is_empty_from_len::generate_is_empty_from_len, + generate_mut_trait_impl::generate_mut_trait_impl, generate_new::generate_new, generate_trait_from_impl::generate_trait_from_impl, inline_call::inline_call, @@ -307,39 +305,41 @@ mod handlers { inline_const_as_literal::inline_const_as_literal, inline_local_variable::inline_local_variable, inline_macro::inline_macro, - inline_type_alias::inline_type_alias, inline_type_alias::inline_type_alias_uses, + inline_type_alias::inline_type_alias, into_to_qualified_from::into_to_qualified_from, - introduce_named_generic::introduce_named_generic, introduce_named_lifetime::introduce_named_lifetime, + introduce_named_type_parameter::introduce_named_type_parameter, invert_if::invert_if, merge_imports::merge_imports, merge_match_arms::merge_match_arms, merge_nested_if::merge_nested_if, move_bounds::move_bounds_to_where_clause, move_const_to_impl::move_const_to_impl, + move_from_mod_rs::move_from_mod_rs, move_guard::move_arm_cond_to_match_guard, move_guard::move_guard_to_arm_body, move_module_to_file::move_module_to_file, move_to_mod_rs::move_to_mod_rs, - move_from_mod_rs::move_from_mod_rs, normalize_import::normalize_import, number_representation::reformat_number_literal, - pull_assignment_up::pull_assignment_up, promote_local_to_const::promote_local_to_const, - qualify_path::qualify_path, + pull_assignment_up::pull_assignment_up, qualify_method_call::qualify_method_call, + qualify_path::qualify_path, raw_string::add_hash, raw_string::make_usual_string, raw_string::remove_hash, remove_dbg::remove_dbg, remove_mut::remove_mut, + remove_parentheses::remove_parentheses, remove_unused_imports::remove_unused_imports, remove_unused_param::remove_unused_param, - remove_parentheses::remove_parentheses, reorder_fields::reorder_fields, reorder_impl_items::reorder_impl_items, - replace_try_expr_with_match::replace_try_expr_with_match, + replace_arith_op::replace_arith_with_checked, + replace_arith_op::replace_arith_with_saturating, + replace_arith_op::replace_arith_with_wrapping, replace_derive_with_manual_impl::replace_derive_with_manual_impl, replace_if_let_with_match::replace_if_let_with_match, replace_if_let_with_match::replace_match_with_if_let, @@ -348,23 +348,23 @@ mod handlers { replace_method_eager_lazy::replace_with_eager_method, replace_method_eager_lazy::replace_with_lazy_method, replace_named_generic_with_impl::replace_named_generic_with_impl, - replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type, replace_qualified_name_with_use::replace_qualified_name_with_use, - replace_arith_op::replace_arith_with_wrapping, - replace_arith_op::replace_arith_with_checked, - replace_arith_op::replace_arith_with_saturating, + replace_try_expr_with_match::replace_try_expr_with_match, + replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type, sort_items::sort_items, split_import::split_import, term_search::term_search, + toggle_async_sugar::desugar_async_into_impl_future, + toggle_async_sugar::sugar_impl_future_into_async, toggle_ignore::toggle_ignore, toggle_macro_delimiter::toggle_macro_delimiter, unmerge_match_arm::unmerge_match_arm, unmerge_use::unmerge_use, unnecessary_async::unnecessary_async, + unqualify_method_call::unqualify_method_call, unwrap_block::unwrap_block, unwrap_return_type::unwrap_return_type, unwrap_tuple::unwrap_tuple, - unqualify_method_call::unqualify_method_call, wrap_return_type::wrap_return_type, wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr, diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs index 91c1a3e1bd79..4234124d670f 100644 --- a/crates/ide-assists/src/tests/generated.rs +++ b/crates/ide-assists/src/tests/generated.rs @@ -27,6 +27,29 @@ fn foo(n: i32) -> i32 { ) } +#[test] +fn doctest_add_explicit_enum_discriminant() { + check_doc_test( + "add_explicit_enum_discriminant", + r#####" +enum TheEnum$0 { + Foo, + Bar, + Baz = 42, + Quux, +} +"#####, + r#####" +enum TheEnum { + Foo = 0, + Bar = 1, + Baz = 42, + Quux = 43, +} +"#####, + ) +} + #[test] fn doctest_add_explicit_type() { check_doc_test( @@ -304,34 +327,6 @@ fn some_function(x: i32) { ) } -#[test] -fn doctest_bool_to_enum() { - check_doc_test( - "bool_to_enum", - r#####" -fn main() { - let $0bool = true; - - if bool { - println!("foo"); - } -} -"#####, - r#####" -#[derive(PartialEq, Eq)] -enum Bool { True, False } - -fn main() { - let bool = Bool::True; - - if bool == Bool::True { - println!("foo"); - } -} -"#####, - ) -} - #[test] fn doctest_change_visibility() { check_doc_test( @@ -382,6 +377,34 @@ fn main() { ) } +#[test] +fn doctest_convert_bool_to_enum() { + check_doc_test( + "convert_bool_to_enum", + r#####" +fn main() { + let $0bool = true; + + if bool { + println!("foo"); + } +} +"#####, + r#####" +#[derive(PartialEq, Eq)] +enum Bool { True, False } + +fn main() { + let bool = Bool::True; + + if bool == Bool::True { + println!("foo"); + } +} +"#####, + ) +} + #[test] fn doctest_convert_closure_to_fn() { check_doc_test( @@ -933,23 +956,42 @@ pub use foo::{Bar, Baz}; } #[test] -fn doctest_explicit_enum_discriminant() { +fn doctest_expand_record_rest_pattern() { check_doc_test( - "explicit_enum_discriminant", + "expand_record_rest_pattern", r#####" -enum TheEnum$0 { - Foo, - Bar, - Baz = 42, - Quux, +struct Bar { y: Y, z: Z } + +fn foo(bar: Bar) { + let Bar { ..$0 } = bar; } "#####, r#####" -enum TheEnum { - Foo = 0, - Bar = 1, - Baz = 42, - Quux = 43, +struct Bar { y: Y, z: Z } + +fn foo(bar: Bar) { + let Bar { y, z } = bar; +} +"#####, + ) +} + +#[test] +fn doctest_expand_tuple_struct_rest_pattern() { + check_doc_test( + "expand_tuple_struct_rest_pattern", + r#####" +struct Bar(Y, Z); + +fn foo(bar: Bar) { + let Bar(..$0) = bar; +} +"#####, + r#####" +struct Bar(Y, Z); + +fn foo(bar: Bar) { + let Bar(_0, _1) = bar; } "#####, ) @@ -1117,27 +1159,6 @@ 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( @@ -2193,19 +2214,6 @@ fn main() -> () { ) } -#[test] -fn doctest_introduce_named_generic() { - check_doc_test( - "introduce_named_generic", - r#####" -fn foo(bar: $0impl Bar) {} -"#####, - r#####" -fn foo<$0B: Bar>(bar: B) {} -"#####, - ) -} - #[test] fn doctest_introduce_named_lifetime() { check_doc_test( @@ -2231,6 +2239,19 @@ impl<'a> Cursor<'a> { ) } +#[test] +fn doctest_introduce_named_type_parameter() { + check_doc_test( + "introduce_named_type_parameter", + r#####" +fn foo(bar: $0impl Bar) {} +"#####, + r#####" +fn foo<$0B: Bar>(bar: B) {} +"#####, + ) +} + #[test] fn doctest_invert_if() { check_doc_test( diff --git a/docs/book/src/assists_generated.md b/docs/book/src/assists_generated.md index c2063df50689..571113178d67 100644 --- a/docs/book/src/assists_generated.md +++ b/docs/book/src/assists_generated.md @@ -28,6 +28,32 @@ fn foo(n: i32) -> i32 { ``` +### `add_explicit_enum_discriminant` +**Source:** [add_explicit_enum_discriminant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs#L11) + +Adds explicit discriminant to all enum variants. + +#### Before +```rust +enum TheEnum┃ { + Foo, + Bar, + Baz = 42, + Quux, +} +``` + +#### After +```rust +enum TheEnum { + Foo = 0, + Bar = 1, + Baz = 42, + Quux = 43, +} +``` + + ### `add_explicit_type` **Source:** [add_explicit_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_explicit_type.rs#L7) @@ -350,40 +376,6 @@ fn some_function(x: i32) { ``` -### `bool_to_enum` -**Source:** [bool_to_enum.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/bool_to_enum.rs#L29) - -This converts boolean local variables, fields, constants, and statics into a new -enum with two variants `Bool::True` and `Bool::False`, as well as replacing -all assignments with the variants and replacing all usages with `== Bool::True` or -`== Bool::False`. - -#### Before -```rust -fn main() { - let ┃bool = true; - - if bool { - println!("foo"); - } -} -``` - -#### After -```rust -#[derive(PartialEq, Eq)] -enum Bool { True, False } - -fn main() { - let bool = Bool::True; - - if bool == Bool::True { - println!("foo"); - } -} -``` - - ### `change_visibility` **Source:** [change_visibility.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/change_visibility.rs#L13) @@ -442,6 +434,40 @@ fn main() { ``` +### `convert_bool_to_enum` +**Source:** [convert_bool_to_enum.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_bool_to_enum.rs#L29) + +This converts boolean local variables, fields, constants, and statics into a new +enum with two variants `Bool::True` and `Bool::False`, as well as replacing +all assignments with the variants and replacing all usages with `== Bool::True` or +`== Bool::False`. + +#### Before +```rust +fn main() { + let ┃bool = true; + + if bool { + println!("foo"); + } +} +``` + +#### After +```rust +#[derive(PartialEq, Eq)] +enum Bool { True, False } + +fn main() { + let bool = Bool::True; + + if bool == Bool::True { + println!("foo"); + } +} +``` + + ### `convert_closure_to_fn` **Source:** [convert_closure_to_fn.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_closure_to_fn.rs#L27) @@ -1043,28 +1069,50 @@ pub use foo::{Bar, Baz}; ``` -### `explicit_enum_discriminant` -**Source:** [explicit_enum_discriminant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs#L11) +### `expand_record_rest_pattern` +**Source:** [expand_rest_pattern.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/expand_rest_pattern.rs#L24) -Adds explicit discriminant to all enum variants. +Fills fields by replacing rest pattern in record patterns. #### Before ```rust -enum TheEnum┃ { - Foo, - Bar, - Baz = 42, - Quux, +struct Bar { y: Y, z: Z } + +fn foo(bar: Bar) { + let Bar { ..┃ } = bar; } ``` #### After ```rust -enum TheEnum { - Foo = 0, - Bar = 1, - Baz = 42, - Quux = 43, +struct Bar { y: Y, z: Z } + +fn foo(bar: Bar) { + let Bar { y, z } = bar; +} +``` + + +### `expand_tuple_struct_rest_pattern` +**Source:** [expand_rest_pattern.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/expand_rest_pattern.rs#L80) + +Fills fields by replacing rest pattern in tuple struct patterns. + +#### Before +```rust +struct Bar(Y, Z); + +fn foo(bar: Bar) { + let Bar(..┃) = bar; +} +``` + +#### After +```rust +struct Bar(Y, Z); + +fn foo(bar: Bar) { + let Bar(_0, _1) = bar; } ``` @@ -1255,30 +1303,6 @@ fn main() { ``` -### `fill_record_pattern_fields` -**Source:** [fill_record_pattern_fields.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs#L8) - -Fills fields by replacing rest pattern in record patterns. - -#### Before -```rust -struct Bar { y: Y, z: Z } - -fn foo(bar: Bar) { - let Bar { ..┃ } = bar; -} -``` - -#### After -```rust -struct Bar { y: Y, z: Z } - -fn foo(bar: Bar) { - let Bar { y, z } = bar; -} -``` - - ### `fix_visibility` **Source:** [fix_visibility.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/fix_visibility.rs#L14) @@ -2423,22 +2447,6 @@ fn main() -> () { ``` -### `introduce_named_generic` -**Source:** [introduce_named_generic.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/introduce_named_generic.rs#L7) - -Replaces `impl Trait` function argument with the named generic. - -#### Before -```rust -fn foo(bar: ┃impl Bar) {} -``` - -#### After -```rust -fn foo<┃B: Bar>(bar: B) {} -``` - - ### `introduce_named_lifetime` **Source:** [introduce_named_lifetime.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/introduce_named_lifetime.rs#L13) @@ -2467,6 +2475,22 @@ impl<'a> Cursor<'a> { ``` +### `introduce_named_type_parameter` +**Source:** [introduce_named_type_parameter.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/introduce_named_type_parameter.rs#L7) + +Replaces `impl Trait` function argument with the named generic. + +#### Before +```rust +fn foo(bar: ┃impl Bar) {} +``` + +#### After +```rust +fn foo<┃B: Bar>(bar: B) {} +``` + + ### `invert_if` **Source:** [invert_if.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/invert_if.rs#L13)