diff options
Diffstat (limited to 'crates/ra_assists/src/assists/invert_if.rs')
-rw-r--r-- | crates/ra_assists/src/assists/invert_if.rs | 55 |
1 files changed, 34 insertions, 21 deletions
diff --git a/crates/ra_assists/src/assists/invert_if.rs b/crates/ra_assists/src/assists/invert_if.rs index c2c8529fe..bababa3e2 100644 --- a/crates/ra_assists/src/assists/invert_if.rs +++ b/crates/ra_assists/src/assists/invert_if.rs | |||
@@ -1,8 +1,7 @@ | |||
1 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
2 | use ra_syntax::ast::{self, AstNode}; | 2 | use ra_syntax::ast::{self, AstNode}; |
3 | use ra_syntax::{TextRange, TextUnit}; | 3 | use ra_syntax::T; |
4 | 4 | ||
5 | use super::apply_demorgan::undo_negation; | ||
6 | use crate::{Assist, AssistCtx, AssistId}; | 5 | use crate::{Assist, AssistCtx, AssistId}; |
7 | 6 | ||
8 | // Assist: invert_if | 7 | // Assist: invert_if |
@@ -14,42 +13,56 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
14 | // | 13 | // |
15 | // ``` | 14 | // ``` |
16 | // fn main() { | 15 | // fn main() { |
17 | // if<|> !y {A} else {B} | 16 | // if<|> !y { A } else { B } |
18 | // } | 17 | // } |
19 | // ``` | 18 | // ``` |
20 | // -> | 19 | // -> |
21 | // ``` | 20 | // ``` |
22 | // fn main() { | 21 | // fn main() { |
23 | // if y {B} else {A} | 22 | // if y { B } else { A } |
24 | // } | 23 | // } |
25 | // ``` | 24 | // ``` |
26 | 25 | ||
27 | pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | 26 | pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { |
28 | let expr = ctx.find_node_at_offset::<ast::IfExpr>()?; | 27 | let if_keyword = ctx.find_token_at_offset(T![if])?; |
29 | let expr_range = expr.syntax().text_range(); | 28 | let expr = ast::IfExpr::cast(if_keyword.parent())?; |
30 | let if_range = TextRange::offset_len(expr_range.start(), TextUnit::from_usize(2)); | 29 | let if_range = if_keyword.text_range(); |
31 | let cursor_in_range = ctx.frange.range.is_subrange(&if_range); | 30 | let cursor_in_range = ctx.frange.range.is_subrange(&if_range); |
32 | if !cursor_in_range { | 31 | if !cursor_in_range { |
33 | return None; | 32 | return None; |
34 | } | 33 | } |
35 | 34 | ||
36 | let cond = expr.condition()?.expr()?.syntax().clone(); | 35 | let cond = expr.condition()?.expr()?; |
37 | let then_node = expr.then_branch()?.syntax().clone(); | 36 | let then_node = expr.then_branch()?.syntax().clone(); |
38 | 37 | ||
39 | if let ast::ElseBranch::Block(else_block) = expr.else_branch()? { | 38 | if let ast::ElseBranch::Block(else_block) = expr.else_branch()? { |
40 | let flip_cond = undo_negation(cond.clone())?; | 39 | let flip_cond = invert_boolean_expression(&cond)?; |
41 | let cond_range = cond.text_range(); | 40 | let cond_range = cond.syntax().text_range(); |
42 | let else_node = else_block.syntax(); | 41 | let else_node = else_block.syntax(); |
43 | let else_range = else_node.text_range(); | 42 | let else_range = else_node.text_range(); |
44 | let then_range = then_node.text_range(); | 43 | let then_range = then_node.text_range(); |
45 | ctx.add_assist(AssistId("invert_if"), "invert if branches", |edit| { | 44 | return ctx.add_assist(AssistId("invert_if"), "invert if branches", |edit| { |
46 | edit.target(if_range); | 45 | edit.target(if_range); |
47 | edit.replace(cond_range, flip_cond); | 46 | edit.replace(cond_range, flip_cond.syntax().text()); |
48 | edit.replace(else_range, then_node.text()); | 47 | edit.replace(else_range, then_node.text()); |
49 | edit.replace(then_range, else_node.text()); | 48 | edit.replace(then_range, else_node.text()); |
50 | }) | 49 | }); |
51 | } else { | 50 | } |
52 | None | 51 | |
52 | None | ||
53 | } | ||
54 | |||
55 | pub(crate) fn invert_boolean_expression(expr: &ast::Expr) -> Option<ast::Expr> { | ||
56 | match expr { | ||
57 | ast::Expr::BinExpr(bin) => match bin.op_kind()? { | ||
58 | ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()), | ||
59 | _ => None, | ||
60 | }, | ||
61 | ast::Expr::PrefixExpr(pe) => match pe.op_kind()? { | ||
62 | ast::PrefixOp::Not => pe.expr(), | ||
63 | _ => None, | ||
64 | }, | ||
65 | _ => None, | ||
53 | } | 66 | } |
54 | } | 67 | } |
55 | 68 | ||
@@ -63,8 +76,8 @@ mod tests { | |||
63 | fn invert_if_remove_inequality() { | 76 | fn invert_if_remove_inequality() { |
64 | check_assist( | 77 | check_assist( |
65 | invert_if, | 78 | invert_if, |
66 | "fn f() { i<|>f x != 3 {1} else {3 + 2} }", | 79 | "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }", |
67 | "fn f() { i<|>f x == 3 {3 + 2} else {1} }", | 80 | "fn f() { i<|>f x == 3 { 3 + 2 } else { 1 } }", |
68 | ) | 81 | ) |
69 | } | 82 | } |
70 | 83 | ||
@@ -72,18 +85,18 @@ mod tests { | |||
72 | fn invert_if_remove_not() { | 85 | fn invert_if_remove_not() { |
73 | check_assist( | 86 | check_assist( |
74 | invert_if, | 87 | invert_if, |
75 | "fn f() { <|>if !cond {3 * 2} else {1} }", | 88 | "fn f() { <|>if !cond { 3 * 2 } else { 1 } }", |
76 | "fn f() { <|>if cond {1} else {3 * 2} }", | 89 | "fn f() { <|>if cond { 1 } else { 3 * 2 } }", |
77 | ) | 90 | ) |
78 | } | 91 | } |
79 | 92 | ||
80 | #[test] | 93 | #[test] |
81 | fn invert_if_doesnt_apply_with_cursor_not_on_if() { | 94 | fn invert_if_doesnt_apply_with_cursor_not_on_if() { |
82 | check_assist_not_applicable(invert_if, "fn f() { if !<|>cond {3 * 2} else {1} }") | 95 | check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }") |
83 | } | 96 | } |
84 | 97 | ||
85 | #[test] | 98 | #[test] |
86 | fn invert_if_doesnt_apply_without_negated() { | 99 | fn invert_if_doesnt_apply_without_negated() { |
87 | check_assist_not_applicable(invert_if, "fn f() { i<|>f cond {3 * 2} else {1} }") | 100 | check_assist_not_applicable(invert_if, "fn f() { i<|>f cond { 3 * 2 } else { 1 } }") |
88 | } | 101 | } |
89 | } | 102 | } |