From e0f08fcc20ba18a8225b5c591b8b5429090d1943 Mon Sep 17 00:00:00 2001 From: Domantas Jadenkus Date: Sun, 14 Feb 2021 19:26:37 +0200 Subject: add generate_enum_as_method assist --- .../src/handlers/generate_enum_match_method.rs | 124 +++++++++++++++++++++ crates/ide_assists/src/lib.rs | 1 + crates/ide_assists/src/tests/generated.rs | 29 +++++ 3 files changed, 154 insertions(+) (limited to 'crates/ide_assists') diff --git a/crates/ide_assists/src/handlers/generate_enum_match_method.rs b/crates/ide_assists/src/handlers/generate_enum_match_method.rs index b271b48b6..45a08acad 100644 --- a/crates/ide_assists/src/handlers/generate_enum_match_method.rs +++ b/crates/ide_assists/src/handlers/generate_enum_match_method.rs @@ -145,6 +145,79 @@ pub(crate) fn generate_enum_into_method(acc: &mut Assists, ctx: &AssistContext) ) } +// Assist: generate_enum_as_method +// +// Generate an `as_` method for an enum variant. +// +// ``` +// enum Value { +// Number(i32), +// Text(String)$0, +// } +// ``` +// -> +// ``` +// enum Value { +// Number(i32), +// Text(String), +// } +// +// impl Value { +// fn as_text(&self) -> Option<&String> { +// if let Self::Text(v) = self { +// Some(v) +// } else { +// None +// } +// } +// } +// ``` +pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { + let variant = ctx.find_node_at_offset::()?; + let variant_name = variant.name()?; + let parent_enum = ast::Adt::Enum(variant.parent_enum()); + let variant_kind = variant_kind(&variant); + + let fn_name = format!("as_{}", &to_lower_snake_case(variant_name.text())); + + // Return early if we've found an existing new fn + let impl_def = find_struct_impl( + &ctx, + &parent_enum, + &fn_name, + )?; + + let field_type = variant_kind.single_field_type()?; + let (pattern_suffix, bound_name) = variant_kind.binding_pattern()?; + + let target = variant.syntax().text_range(); + acc.add( + AssistId("generate_enum_as_method", AssistKind::Generate), + "Generate an `as_` method for an enum variant", + target, + |builder| { + let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v)); + let method = format!( + " {}fn {}(&self) -> Option<&{}> {{ + if let Self::{}{} = self {{ + Some({}) + }} else {{ + None + }} + }}", + vis, + fn_name, + field_type.syntax(), + variant_name, + pattern_suffix, + bound_name, + ); + + add_method_to_adt(builder, &parent_enum, impl_def, &method); + }, + ) +} + fn add_method_to_adt( builder: &mut AssistBuilder, adt: &ast::Adt, @@ -527,6 +600,57 @@ impl Value { None } } +}"#, + ); + } + + #[test] + fn test_generate_enum_as_tuple_variant() { + check_assist( + generate_enum_as_method, + r#" +enum Value { + Number(i32), + Text(String)$0, +}"#, + r#"enum Value { + Number(i32), + Text(String), +} + +impl Value { + fn as_text(&self) -> Option<&String> { + if let Self::Text(v) = self { + Some(v) + } else { + None + } + } +}"#, + ); + } + + #[test] + fn test_generate_enum_as_record_variant() { + check_assist( + generate_enum_as_method, + r#"enum Value { + Number(i32), + Text { text: String }$0, +}"#, + r#"enum Value { + Number(i32), + Text { text: String }, +} + +impl Value { + fn as_text(&self) -> Option<&String> { + if let Self::Text { text } = self { + Some(text) + } else { + None + } + } }"#, ); } diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 2ce59e39a..84ac928e9 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs @@ -191,6 +191,7 @@ mod handlers { generate_derive::generate_derive, generate_enum_match_method::generate_enum_is_method, generate_enum_match_method::generate_enum_into_method, + generate_enum_match_method::generate_enum_as_method, generate_from_impl_for_enum::generate_from_impl_for_enum, generate_function::generate_function, generate_getter::generate_getter, diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs index 39f48dd76..14b372c62 100644 --- a/crates/ide_assists/src/tests/generated.rs +++ b/crates/ide_assists/src/tests/generated.rs @@ -482,6 +482,35 @@ struct Point { ) } +#[test] +fn doctest_generate_enum_as_method() { + check_doc_test( + "generate_enum_as_method", + r#####" +enum Value { + Number(i32), + Text(String)$0, +} +"#####, + r#####" +enum Value { + Number(i32), + Text(String), +} + +impl Value { + fn as_text(&self) -> Option<&String> { + if let Self::Text(v) = self { + Some(v) + } else { + None + } + } +} +"#####, + ) +} + #[test] fn doctest_generate_enum_into_method() { check_doc_test( -- cgit v1.2.3