diff options
-rw-r--r-- | crates/ra_assists/src/assists/apply_demorgan.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/assists/invert_if.rs | 85 | ||||
-rw-r--r-- | crates/ra_assists/src/doc_tests/generated.rs | 17 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | docs/user/assists.md | 19 |
5 files changed, 124 insertions, 1 deletions
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs index 068da1774..0d59a0d24 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/assists/apply_demorgan.rs | |||
@@ -57,7 +57,7 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> { | |||
57 | } | 57 | } |
58 | 58 | ||
59 | // This function tries to undo unary negation, or inequality | 59 | // This function tries to undo unary negation, or inequality |
60 | fn undo_negation(node: SyntaxNode) -> Option<String> { | 60 | pub(crate) fn undo_negation(node: SyntaxNode) -> Option<String> { |
61 | match ast::Expr::cast(node)? { | 61 | match ast::Expr::cast(node)? { |
62 | ast::Expr::BinExpr(bin) => match bin.op_kind()? { | 62 | ast::Expr::BinExpr(bin) => match bin.op_kind()? { |
63 | ast::BinOp::NegatedEqualityTest => { | 63 | ast::BinOp::NegatedEqualityTest => { |
diff --git a/crates/ra_assists/src/assists/invert_if.rs b/crates/ra_assists/src/assists/invert_if.rs new file mode 100644 index 000000000..9a53a3d18 --- /dev/null +++ b/crates/ra_assists/src/assists/invert_if.rs | |||
@@ -0,0 +1,85 @@ | |||
1 | use hir::db::HirDatabase; | ||
2 | use ra_syntax::ast::{self, AstNode}; | ||
3 | use ra_syntax::{TextRange, TextUnit}; | ||
4 | |||
5 | use crate::{Assist, AssistCtx, AssistId}; | ||
6 | use super::apply_demorgan::undo_negation; | ||
7 | |||
8 | // Assist: invert_if | ||
9 | // | ||
10 | // Apply invert_if | ||
11 | // This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}` | ||
12 | // This also works with `!=`. This assist can only be applied with the cursor | ||
13 | // on `if`. | ||
14 | // | ||
15 | // ``` | ||
16 | // fn main() { | ||
17 | // if<|> !y {A} else {B} | ||
18 | // } | ||
19 | // ``` | ||
20 | // -> | ||
21 | // ``` | ||
22 | // fn main() { | ||
23 | // if y {B} else {A} | ||
24 | // } | ||
25 | // ``` | ||
26 | |||
27 | |||
28 | pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
29 | let expr = ctx.find_node_at_offset::<ast::IfExpr>()?; | ||
30 | let expr_range = expr.syntax().text_range(); | ||
31 | let if_range = TextRange::offset_len(expr_range.start(), TextUnit::from_usize(2)); | ||
32 | let cursor_in_range = ctx.frange.range.is_subrange(&if_range); | ||
33 | if !cursor_in_range { | ||
34 | return None; | ||
35 | } | ||
36 | |||
37 | let cond = expr.condition()?.expr()?.syntax().clone(); | ||
38 | let then_node = expr.then_branch()?.syntax().clone(); | ||
39 | |||
40 | if let ast::ElseBranch::Block(else_block) = expr.else_branch()? { | ||
41 | let flip_cond = undo_negation(cond.clone())?; | ||
42 | let cond_range = cond.text_range(); | ||
43 | let else_node = else_block.syntax(); | ||
44 | let else_range = else_node.text_range(); | ||
45 | let then_range = then_node.text_range(); | ||
46 | ctx.add_assist(AssistId("invert_if"), "invert if branches", |edit| { | ||
47 | edit.target(if_range); | ||
48 | edit.replace(cond_range, flip_cond); | ||
49 | edit.replace(else_range, then_node.text()); | ||
50 | edit.replace(then_range, else_node.text()); | ||
51 | }) | ||
52 | |||
53 | } else { | ||
54 | None | ||
55 | } | ||
56 | |||
57 | |||
58 | } | ||
59 | |||
60 | #[cfg(test)] | ||
61 | mod tests { | ||
62 | use super::*; | ||
63 | |||
64 | use crate::helpers::{check_assist, check_assist_not_applicable}; | ||
65 | |||
66 | #[test] | ||
67 | fn invert_if_remove_inequality() { | ||
68 | check_assist(invert_if, "fn f() { i<|>f x != 3 {1} else {3 + 2} }", "fn f() { i<|>f x == 3 {3 + 2} else {1} }") | ||
69 | } | ||
70 | |||
71 | #[test] | ||
72 | fn invert_if_remove_not() { | ||
73 | check_assist(invert_if, "fn f() { <|>if !cond {3 * 2} else {1} }", "fn f() { <|>if cond {1} else {3 * 2} }") | ||
74 | } | ||
75 | |||
76 | #[test] | ||
77 | fn invert_if_doesnt_apply_with_cursor_not_on_if() { | ||
78 | check_assist_not_applicable(invert_if, "fn f() { if !<|>cond {3 * 2} else {1} }") | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn invert_if_doesnt_apply_without_negated() { | ||
83 | check_assist_not_applicable(invert_if, "fn f() { i<|>f cond {3 * 2} else {1} }") | ||
84 | } | ||
85 | } | ||
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 176761efb..1ccc016d3 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -342,6 +342,23 @@ fn main() { | |||
342 | } | 342 | } |
343 | 343 | ||
344 | #[test] | 344 | #[test] |
345 | fn doctest_invert_if() { | ||
346 | check( | ||
347 | "invert_if", | ||
348 | r#####" | ||
349 | fn main() { | ||
350 | if<|> !y {A} else {B} | ||
351 | } | ||
352 | "#####, | ||
353 | r#####" | ||
354 | fn main() { | ||
355 | if y {B} else {A} | ||
356 | } | ||
357 | "#####, | ||
358 | ) | ||
359 | } | ||
360 | |||
361 | #[test] | ||
345 | fn doctest_make_raw_string() { | 362 | fn doctest_make_raw_string() { |
346 | check( | 363 | check( |
347 | "make_raw_string", | 364 | "make_raw_string", |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index f2f0dacbf..a372bd8b9 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -97,6 +97,7 @@ mod assists { | |||
97 | mod add_impl; | 97 | mod add_impl; |
98 | mod add_new; | 98 | mod add_new; |
99 | mod apply_demorgan; | 99 | mod apply_demorgan; |
100 | mod invert_if; | ||
100 | mod flip_comma; | 101 | mod flip_comma; |
101 | mod flip_binexpr; | 102 | mod flip_binexpr; |
102 | mod flip_trait_bound; | 103 | mod flip_trait_bound; |
@@ -122,6 +123,7 @@ mod assists { | |||
122 | add_impl::add_impl, | 123 | add_impl::add_impl, |
123 | add_new::add_new, | 124 | add_new::add_new, |
124 | apply_demorgan::apply_demorgan, | 125 | apply_demorgan::apply_demorgan, |
126 | invert_if::invert_if, | ||
125 | change_visibility::change_visibility, | 127 | change_visibility::change_visibility, |
126 | fill_match_arms::fill_match_arms, | 128 | fill_match_arms::fill_match_arms, |
127 | merge_match_arms::merge_match_arms, | 129 | merge_match_arms::merge_match_arms, |
diff --git a/docs/user/assists.md b/docs/user/assists.md index 8da7578e2..6e7811bd6 100644 --- a/docs/user/assists.md +++ b/docs/user/assists.md | |||
@@ -329,6 +329,25 @@ fn main() { | |||
329 | } | 329 | } |
330 | ``` | 330 | ``` |
331 | 331 | ||
332 | ## `invert_if` | ||
333 | |||
334 | Apply invert_if | ||
335 | This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}` | ||
336 | This also works with `!=`. This assist can only be applied with the cursor | ||
337 | on `if`. | ||
338 | |||
339 | ```rust | ||
340 | // BEFORE | ||
341 | fn main() { | ||
342 | if┃ !y {A} else {B} | ||
343 | } | ||
344 | |||
345 | // AFTER | ||
346 | fn main() { | ||
347 | if y {B} else {A} | ||
348 | } | ||
349 | ``` | ||
350 | |||
332 | ## `make_raw_string` | 351 | ## `make_raw_string` |
333 | 352 | ||
334 | Adds `r#` to a plain string literal. | 353 | Adds `r#` to a plain string literal. |