Skip to content

Commit 4a24edd

Browse files
bors[bot]jDomantas
andauthored
Merge #7677
7677: More enum matching r=yoshuawuyts a=jDomantas * Renamed existing `generate_enum_match_method` to `generate_enum_is_variant` * Added two similar assists to generate `into_` and `as_` methods. * Made all of them general enough to work on record and tuple variants too. For `as_` method generation there's room to improve: * Right now it always returns `Option<&Field>`, even though `Option<Field>` would be nicer when `Field: Copy`. I don't know how to check if the field type implements `Copy`. If given suggestions I could try to fix this in a follow-up pr. * `&String` could be replaced with `&str`, `&Box<_>` with `&_`, and probably some more. I don't know what would be a good way to do that. Closes #7604 Co-authored-by: Domantas Jadenkus <djadenkus@gmail.com>
2 parents 2a4076c + 558bcf4 commit 4a24edd

File tree

5 files changed

+488
-64
lines changed

5 files changed

+488
-64
lines changed

crates/ide_assists/src/handlers/generate_enum_match_method.rs renamed to crates/ide_assists/src/handlers/generate_enum_is_method.rs

Lines changed: 69 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
use stdx::{format_to, to_lower_snake_case};
1+
use stdx::to_lower_snake_case;
22
use syntax::ast::VisibilityOwner;
33
use syntax::ast::{self, AstNode, NameOwner};
4-
use test_utils::mark;
54

65
use crate::{
7-
utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
6+
utils::{add_method_to_adt, find_struct_impl},
87
AssistContext, AssistId, AssistKind, Assists,
98
};
109

11-
// Assist: generate_enum_match_method
10+
// Assist: generate_enum_is_method
1211
//
1312
// Generate an `is_` method for an enum variant.
1413
//
@@ -34,79 +33,52 @@ use crate::{
3433
// }
3534
// }
3635
// ```
37-
pub(crate) fn generate_enum_match_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36+
pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
3837
let variant = ctx.find_node_at_offset::<ast::Variant>()?;
3938
let variant_name = variant.name()?;
40-
let parent_enum = variant.parent_enum();
41-
if !matches!(variant.kind(), ast::StructKind::Unit) {
42-
mark::hit!(test_gen_enum_match_on_non_unit_variant_not_implemented);
43-
return None;
44-
}
39+
let parent_enum = ast::Adt::Enum(variant.parent_enum());
40+
let pattern_suffix = match variant.kind() {
41+
ast::StructKind::Record(_) => " { .. }",
42+
ast::StructKind::Tuple(_) => "(..)",
43+
ast::StructKind::Unit => "",
44+
};
4545

4646
let enum_lowercase_name = to_lower_snake_case(&parent_enum.name()?.to_string());
47-
let fn_name = to_lower_snake_case(&variant_name.to_string());
47+
let fn_name = format!("is_{}", &to_lower_snake_case(variant_name.text()));
4848

4949
// Return early if we've found an existing new fn
50-
let impl_def = find_struct_impl(
51-
&ctx,
52-
&ast::Adt::Enum(parent_enum.clone()),
53-
format!("is_{}", fn_name).as_str(),
54-
)?;
50+
let impl_def = find_struct_impl(&ctx, &parent_enum, &fn_name)?;
5551

5652
let target = variant.syntax().text_range();
5753
acc.add(
58-
AssistId("generate_enum_match_method", AssistKind::Generate),
54+
AssistId("generate_enum_is_method", AssistKind::Generate),
5955
"Generate an `is_` method for an enum variant",
6056
target,
6157
|builder| {
62-
let mut buf = String::with_capacity(512);
63-
64-
if impl_def.is_some() {
65-
buf.push('\n');
66-
}
67-
6858
let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
69-
format_to!(
70-
buf,
59+
let method = format!(
7160
" /// Returns `true` if the {} is [`{}`].
72-
{}fn is_{}(&self) -> bool {{
73-
matches!(self, Self::{})
61+
{}fn {}(&self) -> bool {{
62+
matches!(self, Self::{}{})
7463
}}",
75-
enum_lowercase_name,
76-
variant_name,
77-
vis,
78-
fn_name,
79-
variant_name
64+
enum_lowercase_name, variant_name, vis, fn_name, variant_name, pattern_suffix,
8065
);
8166

82-
let start_offset = impl_def
83-
.and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
84-
.unwrap_or_else(|| {
85-
buf = generate_impl_text(&ast::Adt::Enum(parent_enum.clone()), &buf);
86-
parent_enum.syntax().text_range().end()
87-
});
88-
89-
builder.insert(start_offset, buf);
67+
add_method_to_adt(builder, &parent_enum, impl_def, &method);
9068
},
9169
)
9270
}
9371

9472
#[cfg(test)]
9573
mod tests {
96-
use test_utils::mark;
97-
9874
use crate::tests::{check_assist, check_assist_not_applicable};
9975

10076
use super::*;
10177

102-
fn check_not_applicable(ra_fixture: &str) {
103-
check_assist_not_applicable(generate_enum_match_method, ra_fixture)
104-
}
105-
10678
#[test]
107-
fn test_generate_enum_match_from_variant() {
79+
fn test_generate_enum_is_from_variant() {
10880
check_assist(
109-
generate_enum_match_method,
81+
generate_enum_is_method,
11082
r#"
11183
enum Variant {
11284
Undefined,
@@ -129,8 +101,9 @@ impl Variant {
129101
}
130102

131103
#[test]
132-
fn test_generate_enum_match_already_implemented() {
133-
check_not_applicable(
104+
fn test_generate_enum_is_already_implemented() {
105+
check_assist_not_applicable(
106+
generate_enum_is_method,
134107
r#"
135108
enum Variant {
136109
Undefined,
@@ -147,22 +120,59 @@ impl Variant {
147120
}
148121

149122
#[test]
150-
fn test_add_from_impl_no_element() {
151-
mark::check!(test_gen_enum_match_on_non_unit_variant_not_implemented);
152-
check_not_applicable(
123+
fn test_generate_enum_is_from_tuple_variant() {
124+
check_assist(
125+
generate_enum_is_method,
153126
r#"
154127
enum Variant {
155128
Undefined,
156129
Minor(u32)$0,
157130
Major,
131+
}"#,
132+
r#"enum Variant {
133+
Undefined,
134+
Minor(u32),
135+
Major,
136+
}
137+
138+
impl Variant {
139+
/// Returns `true` if the variant is [`Minor`].
140+
fn is_minor(&self) -> bool {
141+
matches!(self, Self::Minor(..))
142+
}
143+
}"#,
144+
);
145+
}
146+
147+
#[test]
148+
fn test_generate_enum_is_from_record_variant() {
149+
check_assist(
150+
generate_enum_is_method,
151+
r#"
152+
enum Variant {
153+
Undefined,
154+
Minor { foo: i32 }$0,
155+
Major,
156+
}"#,
157+
r#"enum Variant {
158+
Undefined,
159+
Minor { foo: i32 },
160+
Major,
161+
}
162+
163+
impl Variant {
164+
/// Returns `true` if the variant is [`Minor`].
165+
fn is_minor(&self) -> bool {
166+
matches!(self, Self::Minor { .. })
167+
}
158168
}"#,
159169
);
160170
}
161171

162172
#[test]
163-
fn test_generate_enum_match_from_variant_with_one_variant() {
173+
fn test_generate_enum_is_from_variant_with_one_variant() {
164174
check_assist(
165-
generate_enum_match_method,
175+
generate_enum_is_method,
166176
r#"enum Variant { Undefi$0ned }"#,
167177
r#"
168178
enum Variant { Undefined }
@@ -177,9 +187,9 @@ impl Variant {
177187
}
178188

179189
#[test]
180-
fn test_generate_enum_match_from_variant_with_visibility_marker() {
190+
fn test_generate_enum_is_from_variant_with_visibility_marker() {
181191
check_assist(
182-
generate_enum_match_method,
192+
generate_enum_is_method,
183193
r#"
184194
pub(crate) enum Variant {
185195
Undefined,
@@ -202,9 +212,9 @@ impl Variant {
202212
}
203213

204214
#[test]
205-
fn test_multiple_generate_enum_match_from_variant() {
215+
fn test_multiple_generate_enum_is_from_variant() {
206216
check_assist(
207-
generate_enum_match_method,
217+
generate_enum_is_method,
208218
r#"
209219
enum Variant {
210220
Undefined,

0 commit comments

Comments
 (0)