aboutsummaryrefslogtreecommitdiff
path: root/crates/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists')
-rw-r--r--crates/assists/src/handlers/generate_default_from_enum_variant.rs175
-rw-r--r--crates/assists/src/handlers/invert_if.rs9
-rw-r--r--crates/assists/src/lib.rs2
-rw-r--r--crates/assists/src/tests/generated.rs27
-rw-r--r--crates/assists/src/utils.rs4
5 files changed, 217 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/generate_default_from_enum_variant.rs b/crates/assists/src/handlers/generate_default_from_enum_variant.rs
new file mode 100644
index 000000000..bcea46735
--- /dev/null
+++ b/crates/assists/src/handlers/generate_default_from_enum_variant.rs
@@ -0,0 +1,175 @@
1use ide_db::helpers::FamousDefs;
2use ide_db::RootDatabase;
3use syntax::ast::{self, AstNode, NameOwner};
4use test_utils::mark;
5
6use crate::{AssistContext, AssistId, AssistKind, Assists};
7
8// Assist: generate_default_from_enum_variant
9//
10// Adds a Default impl for an enum using a variant.
11//
12// ```
13// enum Version {
14// Undefined,
15// Minor<|>,
16// Major,
17// }
18// ```
19// ->
20// ```
21// enum Version {
22// Undefined,
23// Minor,
24// Major,
25// }
26//
27// impl Default for Version {
28// fn default() -> Self {
29// Self::Minor
30// }
31// }
32// ```
33pub(crate) fn generate_default_from_enum_variant(
34 acc: &mut Assists,
35 ctx: &AssistContext,
36) -> Option<()> {
37 let variant = ctx.find_node_at_offset::<ast::Variant>()?;
38 let variant_name = variant.name()?;
39 let enum_name = variant.parent_enum().name()?;
40 if !matches!(variant.kind(), ast::StructKind::Unit) {
41 mark::hit!(test_gen_default_on_non_unit_variant_not_implemented);
42 return None;
43 }
44
45 if existing_default_impl(&ctx.sema, &variant).is_some() {
46 mark::hit!(test_gen_default_impl_already_exists);
47 return None;
48 }
49
50 let target = variant.syntax().text_range();
51 acc.add(
52 AssistId("generate_default_from_enum_variant", AssistKind::Generate),
53 "Generate `Default` impl from this enum variant",
54 target,
55 |edit| {
56 let start_offset = variant.parent_enum().syntax().text_range().end();
57 let buf = format!(
58 r#"
59
60impl Default for {0} {{
61 fn default() -> Self {{
62 Self::{1}
63 }}
64}}"#,
65 enum_name, variant_name
66 );
67 edit.insert(start_offset, buf);
68 },
69 )
70}
71
72fn existing_default_impl(
73 sema: &'_ hir::Semantics<'_, RootDatabase>,
74 variant: &ast::Variant,
75) -> Option<()> {
76 let variant = sema.to_def(variant)?;
77 let enum_ = variant.parent_enum(sema.db);
78 let krate = enum_.module(sema.db).krate();
79
80 let default_trait = FamousDefs(sema, Some(krate)).core_default_Default()?;
81 let enum_type = enum_.ty(sema.db);
82
83 if enum_type.impls_trait(sema.db, default_trait, &[]) {
84 Some(())
85 } else {
86 None
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use test_utils::mark;
93
94 use crate::tests::{check_assist, check_assist_not_applicable};
95
96 use super::*;
97
98 fn check_not_applicable(ra_fixture: &str) {
99 let fixture =
100 format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
101 check_assist_not_applicable(generate_default_from_enum_variant, &fixture)
102 }
103
104 #[test]
105 fn test_generate_default_from_variant() {
106 check_assist(
107 generate_default_from_enum_variant,
108 r#"
109enum Variant {
110 Undefined,
111 Minor<|>,
112 Major,
113}"#,
114 r#"enum Variant {
115 Undefined,
116 Minor,
117 Major,
118}
119
120impl Default for Variant {
121 fn default() -> Self {
122 Self::Minor
123 }
124}"#,
125 );
126 }
127
128 #[test]
129 fn test_generate_default_already_implemented() {
130 mark::check!(test_gen_default_impl_already_exists);
131 check_not_applicable(
132 r#"
133enum Variant {
134 Undefined,
135 Minor<|>,
136 Major,
137}
138
139impl Default for Variant {
140 fn default() -> Self {
141 Self::Minor
142 }
143}"#,
144 );
145 }
146
147 #[test]
148 fn test_add_from_impl_no_element() {
149 mark::check!(test_gen_default_on_non_unit_variant_not_implemented);
150 check_not_applicable(
151 r#"
152enum Variant {
153 Undefined,
154 Minor(u32)<|>,
155 Major,
156}"#,
157 );
158 }
159
160 #[test]
161 fn test_generate_default_from_variant_with_one_variant() {
162 check_assist(
163 generate_default_from_enum_variant,
164 r#"enum Variant { Undefi<|>ned }"#,
165 r#"
166enum Variant { Undefined }
167
168impl Default for Variant {
169 fn default() -> Self {
170 Self::Undefined
171 }
172}"#,
173 );
174 }
175}
diff --git a/crates/assists/src/handlers/invert_if.rs b/crates/assists/src/handlers/invert_if.rs
index ea722b91b..91e2f5c8c 100644
--- a/crates/assists/src/handlers/invert_if.rs
+++ b/crates/assists/src/handlers/invert_if.rs
@@ -69,6 +69,15 @@ mod tests {
69 use crate::tests::{check_assist, check_assist_not_applicable}; 69 use crate::tests::{check_assist, check_assist_not_applicable};
70 70
71 #[test] 71 #[test]
72 fn invert_if_composite_condition() {
73 check_assist(
74 invert_if,
75 "fn f() { i<|>f x == 3 || x == 4 || x == 5 { 1 } else { 3 * 2 } }",
76 "fn f() { if !(x == 3 || x == 4 || x == 5) { 3 * 2 } else { 1 } }",
77 )
78 }
79
80 #[test]
72 fn invert_if_remove_inequality() { 81 fn invert_if_remove_inequality() {
73 check_assist( 82 check_assist(
74 invert_if, 83 invert_if,
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index b8ce7418d..6e736ccb3 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -137,6 +137,7 @@ mod handlers {
137 mod flip_comma; 137 mod flip_comma;
138 mod flip_trait_bound; 138 mod flip_trait_bound;
139 mod generate_derive; 139 mod generate_derive;
140 mod generate_default_from_enum_variant;
140 mod generate_from_impl_for_enum; 141 mod generate_from_impl_for_enum;
141 mod generate_function; 142 mod generate_function;
142 mod generate_impl; 143 mod generate_impl;
@@ -186,6 +187,7 @@ mod handlers {
186 flip_comma::flip_comma, 187 flip_comma::flip_comma,
187 flip_trait_bound::flip_trait_bound, 188 flip_trait_bound::flip_trait_bound,
188 generate_derive::generate_derive, 189 generate_derive::generate_derive,
190 generate_default_from_enum_variant::generate_default_from_enum_variant,
189 generate_from_impl_for_enum::generate_from_impl_for_enum, 191 generate_from_impl_for_enum::generate_from_impl_for_enum,
190 generate_function::generate_function, 192 generate_function::generate_function,
191 generate_impl::generate_impl, 193 generate_impl::generate_impl,
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 853bde09c..cc7c4a343 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -365,6 +365,33 @@ fn foo<T: Copy + Clone>() { }
365} 365}
366 366
367#[test] 367#[test]
368fn doctest_generate_default_from_enum_variant() {
369 check_doc_test(
370 "generate_default_from_enum_variant",
371 r#####"
372enum Version {
373 Undefined,
374 Minor<|>,
375 Major,
376}
377"#####,
378 r#####"
379enum Version {
380 Undefined,
381 Minor,
382 Major,
383}
384
385impl Default for Version {
386 fn default() -> Self {
387 Self::Minor
388 }
389}
390"#####,
391 )
392}
393
394#[test]
368fn doctest_generate_derive() { 395fn doctest_generate_derive() {
369 check_doc_test( 396 check_doc_test(
370 "generate_derive", 397 "generate_derive",
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs
index 01f5c291f..f2cacf7c8 100644
--- a/crates/assists/src/utils.rs
+++ b/crates/assists/src/utils.rs
@@ -212,6 +212,10 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
212 ast::Expr::BinExpr(bin) => match bin.op_kind()? { 212 ast::Expr::BinExpr(bin) => match bin.op_kind()? {
213 ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()), 213 ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()),
214 ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()), 214 ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()),
215 // Parenthesize composite boolean expressions before prefixing `!`
216 ast::BinOp::BooleanAnd | ast::BinOp::BooleanOr => {
217 Some(make::expr_prefix(T![!], make::expr_paren(expr.clone())))
218 }
215 _ => None, 219 _ => None,
216 }, 220 },
217 ast::Expr::MethodCallExpr(mce) => { 221 ast::Expr::MethodCallExpr(mce) => {