Skip to content

Commit e0f08fc

Browse files
committed
add generate_enum_as_method assist
1 parent 6427869 commit e0f08fc

File tree

3 files changed

+154
-0
lines changed

3 files changed

+154
-0
lines changed

crates/ide_assists/src/handlers/generate_enum_match_method.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,79 @@ pub(crate) fn generate_enum_into_method(acc: &mut Assists, ctx: &AssistContext)
145145
)
146146
}
147147

148+
// Assist: generate_enum_as_method
149+
//
150+
// Generate an `as_` method for an enum variant.
151+
//
152+
// ```
153+
// enum Value {
154+
// Number(i32),
155+
// Text(String)$0,
156+
// }
157+
// ```
158+
// ->
159+
// ```
160+
// enum Value {
161+
// Number(i32),
162+
// Text(String),
163+
// }
164+
//
165+
// impl Value {
166+
// fn as_text(&self) -> Option<&String> {
167+
// if let Self::Text(v) = self {
168+
// Some(v)
169+
// } else {
170+
// None
171+
// }
172+
// }
173+
// }
174+
// ```
175+
pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
176+
let variant = ctx.find_node_at_offset::<ast::Variant>()?;
177+
let variant_name = variant.name()?;
178+
let parent_enum = ast::Adt::Enum(variant.parent_enum());
179+
let variant_kind = variant_kind(&variant);
180+
181+
let fn_name = format!("as_{}", &to_lower_snake_case(variant_name.text()));
182+
183+
// Return early if we've found an existing new fn
184+
let impl_def = find_struct_impl(
185+
&ctx,
186+
&parent_enum,
187+
&fn_name,
188+
)?;
189+
190+
let field_type = variant_kind.single_field_type()?;
191+
let (pattern_suffix, bound_name) = variant_kind.binding_pattern()?;
192+
193+
let target = variant.syntax().text_range();
194+
acc.add(
195+
AssistId("generate_enum_as_method", AssistKind::Generate),
196+
"Generate an `as_` method for an enum variant",
197+
target,
198+
|builder| {
199+
let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
200+
let method = format!(
201+
" {}fn {}(&self) -> Option<&{}> {{
202+
if let Self::{}{} = self {{
203+
Some({})
204+
}} else {{
205+
None
206+
}}
207+
}}",
208+
vis,
209+
fn_name,
210+
field_type.syntax(),
211+
variant_name,
212+
pattern_suffix,
213+
bound_name,
214+
);
215+
216+
add_method_to_adt(builder, &parent_enum, impl_def, &method);
217+
},
218+
)
219+
}
220+
148221
fn add_method_to_adt(
149222
builder: &mut AssistBuilder,
150223
adt: &ast::Adt,
@@ -527,6 +600,57 @@ impl Value {
527600
None
528601
}
529602
}
603+
}"#,
604+
);
605+
}
606+
607+
#[test]
608+
fn test_generate_enum_as_tuple_variant() {
609+
check_assist(
610+
generate_enum_as_method,
611+
r#"
612+
enum Value {
613+
Number(i32),
614+
Text(String)$0,
615+
}"#,
616+
r#"enum Value {
617+
Number(i32),
618+
Text(String),
619+
}
620+
621+
impl Value {
622+
fn as_text(&self) -> Option<&String> {
623+
if let Self::Text(v) = self {
624+
Some(v)
625+
} else {
626+
None
627+
}
628+
}
629+
}"#,
630+
);
631+
}
632+
633+
#[test]
634+
fn test_generate_enum_as_record_variant() {
635+
check_assist(
636+
generate_enum_as_method,
637+
r#"enum Value {
638+
Number(i32),
639+
Text { text: String }$0,
640+
}"#,
641+
r#"enum Value {
642+
Number(i32),
643+
Text { text: String },
644+
}
645+
646+
impl Value {
647+
fn as_text(&self) -> Option<&String> {
648+
if let Self::Text { text } = self {
649+
Some(text)
650+
} else {
651+
None
652+
}
653+
}
530654
}"#,
531655
);
532656
}

crates/ide_assists/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ mod handlers {
191191
generate_derive::generate_derive,
192192
generate_enum_match_method::generate_enum_is_method,
193193
generate_enum_match_method::generate_enum_into_method,
194+
generate_enum_match_method::generate_enum_as_method,
194195
generate_from_impl_for_enum::generate_from_impl_for_enum,
195196
generate_function::generate_function,
196197
generate_getter::generate_getter,

crates/ide_assists/src/tests/generated.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,35 @@ struct Point {
482482
)
483483
}
484484

485+
#[test]
486+
fn doctest_generate_enum_as_method() {
487+
check_doc_test(
488+
"generate_enum_as_method",
489+
r#####"
490+
enum Value {
491+
Number(i32),
492+
Text(String)$0,
493+
}
494+
"#####,
495+
r#####"
496+
enum Value {
497+
Number(i32),
498+
Text(String),
499+
}
500+
501+
impl Value {
502+
fn as_text(&self) -> Option<&String> {
503+
if let Self::Text(v) = self {
504+
Some(v)
505+
} else {
506+
None
507+
}
508+
}
509+
}
510+
"#####,
511+
)
512+
}
513+
485514
#[test]
486515
fn doctest_generate_enum_into_method() {
487516
check_doc_test(

0 commit comments

Comments
 (0)