aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs2
-rw-r--r--crates/ra_assists/src/assists/invert_if.rs85
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs17
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--docs/user/assists.md19
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
60fn undo_negation(node: SyntaxNode) -> Option<String> { 60pub(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 @@
1use hir::db::HirDatabase;
2use ra_syntax::ast::{self, AstNode};
3use ra_syntax::{TextRange, TextUnit};
4
5use crate::{Assist, AssistCtx, AssistId};
6use 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
28pub(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)]
61mod 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]
345fn doctest_invert_if() {
346 check(
347 "invert_if",
348 r#####"
349fn main() {
350 if<|> !y {A} else {B}
351}
352"#####,
353 r#####"
354fn main() {
355 if y {B} else {A}
356}
357"#####,
358 )
359}
360
361#[test]
345fn doctest_make_raw_string() { 362fn 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
334Apply invert_if
335This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
336This also works with `!=`. This assist can only be applied with the cursor
337on `if`.
338
339```rust
340// BEFORE
341fn main() {
342 if┃ !y {A} else {B}
343}
344
345// AFTER
346fn main() {
347 if y {B} else {A}
348}
349```
350
332## `make_raw_string` 351## `make_raw_string`
333 352
334Adds `r#` to a plain string literal. 353Adds `r#` to a plain string literal.