diff options
Diffstat (limited to 'crates/assists')
-rw-r--r-- | crates/assists/src/handlers/generate_default_from_enum_variant.rs | 175 | ||||
-rw-r--r-- | crates/assists/src/handlers/invert_if.rs | 9 | ||||
-rw-r--r-- | crates/assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/assists/src/tests/generated.rs | 27 | ||||
-rw-r--r-- | crates/assists/src/utils.rs | 4 |
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 @@ | |||
1 | use ide_db::helpers::FamousDefs; | ||
2 | use ide_db::RootDatabase; | ||
3 | use syntax::ast::{self, AstNode, NameOwner}; | ||
4 | use test_utils::mark; | ||
5 | |||
6 | use 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 | // ``` | ||
33 | pub(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 | |||
60 | impl 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 | |||
72 | fn 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)] | ||
91 | mod 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#" | ||
109 | enum Variant { | ||
110 | Undefined, | ||
111 | Minor<|>, | ||
112 | Major, | ||
113 | }"#, | ||
114 | r#"enum Variant { | ||
115 | Undefined, | ||
116 | Minor, | ||
117 | Major, | ||
118 | } | ||
119 | |||
120 | impl 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#" | ||
133 | enum Variant { | ||
134 | Undefined, | ||
135 | Minor<|>, | ||
136 | Major, | ||
137 | } | ||
138 | |||
139 | impl 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#" | ||
152 | enum 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#" | ||
166 | enum Variant { Undefined } | ||
167 | |||
168 | impl 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] |
368 | fn doctest_generate_default_from_enum_variant() { | ||
369 | check_doc_test( | ||
370 | "generate_default_from_enum_variant", | ||
371 | r#####" | ||
372 | enum Version { | ||
373 | Undefined, | ||
374 | Minor<|>, | ||
375 | Major, | ||
376 | } | ||
377 | "#####, | ||
378 | r#####" | ||
379 | enum Version { | ||
380 | Undefined, | ||
381 | Minor, | ||
382 | Major, | ||
383 | } | ||
384 | |||
385 | impl Default for Version { | ||
386 | fn default() -> Self { | ||
387 | Self::Minor | ||
388 | } | ||
389 | } | ||
390 | "#####, | ||
391 | ) | ||
392 | } | ||
393 | |||
394 | #[test] | ||
368 | fn doctest_generate_derive() { | 395 | fn 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) => { |