aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/assists/invert_if.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/assists/invert_if.rs')
-rw-r--r--crates/ra_assists/src/assists/invert_if.rs55
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 @@
1use hir::db::HirDatabase; 1use hir::db::HirDatabase;
2use ra_syntax::ast::{self, AstNode}; 2use ra_syntax::ast::{self, AstNode};
3use ra_syntax::{TextRange, TextUnit}; 3use ra_syntax::T;
4 4
5use super::apply_demorgan::undo_negation;
6use crate::{Assist, AssistCtx, AssistId}; 5use 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
27pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 26pub(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
55pub(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}