1 use stdx::{format_to, to_lower_snake_case};
2 use syntax::ast::VisibilityOwner;
3 use syntax::ast::{self, AstNode, NameOwner};
7 utils::{find_impl_block, find_struct_impl},
8 AssistContext, AssistId, AssistKind, Assists,
11 // Assist: generate_enum_match_method
13 // Generate an `is_` method for an enum variant.
31 // fn is_minor(&self) -> bool {
32 // matches!(self, Self::Minor)
36 pub(crate) fn generate_enum_match_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
37 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
38 let variant_name = variant.name()?;
39 let parent_enum = variant.parent_enum();
40 if !matches!(variant.kind(), ast::StructKind::Unit) {
41 mark::hit!(test_gen_enum_match_on_non_unit_variant_not_implemented);
45 let fn_name = to_lower_snake_case(&variant_name.to_string());
47 // Return early if we've found an existing new fn
48 let impl_def = find_struct_impl(
50 &ast::AdtDef::Enum(parent_enum.clone()),
51 format!("is_{}", fn_name).as_str(),
54 let target = variant.syntax().text_range();
56 AssistId("generate_enum_match_method", AssistKind::Generate),
57 "Generate an `is_` method for an enum variant",
60 let mut buf = String::with_capacity(512);
62 if impl_def.is_some() {
66 let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
69 " {}fn is_{}(&self) -> bool {{
70 matches!(self, Self::{})
77 let start_offset = impl_def
78 .and_then(|impl_def| find_impl_block(impl_def, &mut buf))
80 buf = generate_impl_text(&parent_enum, &buf);
81 parent_enum.syntax().text_range().end()
84 builder.insert(start_offset, buf);
89 // Generates the surrounding `impl Type { <code> }` including type and lifetime
91 fn generate_impl_text(strukt: &ast::Enum, code: &str) -> String {
92 let mut buf = String::with_capacity(code.len());
93 buf.push_str("\n\nimpl ");
94 buf.push_str(strukt.name().unwrap().text());
95 format_to!(buf, " {{\n{}\n}}", code);
101 use test_utils::mark;
103 use crate::tests::{check_assist, check_assist_not_applicable};
107 fn check_not_applicable(ra_fixture: &str) {
108 check_assist_not_applicable(generate_enum_match_method, ra_fixture)
112 fn test_generate_enum_match_from_variant() {
114 generate_enum_match_method,
128 fn is_minor(&self) -> bool {
129 matches!(self, Self::Minor)
136 fn test_generate_enum_match_already_implemented() {
137 check_not_applicable(
146 fn is_minor(&self) -> bool {
147 matches!(self, Self::Minor)
154 fn test_add_from_impl_no_element() {
155 mark::check!(test_gen_enum_match_on_non_unit_variant_not_implemented);
156 check_not_applicable(
167 fn test_generate_enum_match_from_variant_with_one_variant() {
169 generate_enum_match_method,
170 r#"enum Variant { Undefi$0ned }"#,
172 enum Variant { Undefined }
175 fn is_undefined(&self) -> bool {
176 matches!(self, Self::Undefined)
183 fn test_generate_enum_match_from_variant_with_visibility_marker() {
185 generate_enum_match_method,
187 pub(crate) enum Variant {
192 r#"pub(crate) enum Variant {
199 pub(crate) fn is_minor(&self) -> bool {
200 matches!(self, Self::Minor)