]> git.lizzy.rs Git - rust.git/commitdiff
initial invert_if
authorbravomikekilo <bmk1221@126.com>
Thu, 21 Nov 2019 18:51:40 +0000 (02:51 +0800)
committerbravomikekilo <bmk1221@126.com>
Thu, 21 Nov 2019 18:51:40 +0000 (02:51 +0800)
crates/ra_assists/src/assists/apply_demorgan.rs
crates/ra_assists/src/assists/invert_if.rs [new file with mode: 0644]
crates/ra_assists/src/doc_tests/generated.rs
crates/ra_assists/src/lib.rs
docs/user/assists.md

index 068da1774d98e544ce2aee16b029d680b4f1c002..0d59a0d241be6d59686e7a5ff7f1dc9e2c31e29b 100644 (file)
@@ -57,7 +57,7 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
 }
 
 // This function tries to undo unary negation, or inequality
-fn undo_negation(node: SyntaxNode) -> Option<String> {
+pub(crate) fn undo_negation(node: SyntaxNode) -> Option<String> {
     match ast::Expr::cast(node)? {
         ast::Expr::BinExpr(bin) => match bin.op_kind()? {
             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 (file)
index 0000000..9a53a3d
--- /dev/null
@@ -0,0 +1,85 @@
+use hir::db::HirDatabase;
+use ra_syntax::ast::{self, AstNode};
+use ra_syntax::{TextRange, TextUnit};
+
+use crate::{Assist, AssistCtx, AssistId};
+use super::apply_demorgan::undo_negation;
+
+// Assist: invert_if
+//
+// Apply invert_if
+// This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
+// This also works with `!=`. This assist can only be applied with the cursor
+// on `if`.
+//
+// ```
+// fn main() {
+//     if<|> !y {A} else {B}
+// }
+// ```
+// ->
+// ```
+// fn main() {
+//     if y {B} else {A}
+// }
+// ```
+
+
+pub(crate) fn invert_if(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
+    let expr = ctx.find_node_at_offset::<ast::IfExpr>()?;
+    let expr_range = expr.syntax().text_range();
+    let if_range = TextRange::offset_len(expr_range.start(), TextUnit::from_usize(2));
+    let cursor_in_range = ctx.frange.range.is_subrange(&if_range);
+    if !cursor_in_range {
+        return None;
+    }
+
+    let cond = expr.condition()?.expr()?.syntax().clone();
+    let then_node = expr.then_branch()?.syntax().clone();
+
+    if let ast::ElseBranch::Block(else_block) = expr.else_branch()? {
+        let flip_cond = undo_negation(cond.clone())?;
+        let cond_range = cond.text_range();
+        let else_node = else_block.syntax();
+        let else_range = else_node.text_range();
+        let then_range = then_node.text_range();
+        ctx.add_assist(AssistId("invert_if"), "invert if branches", |edit| {
+            edit.target(if_range);
+            edit.replace(cond_range, flip_cond);
+            edit.replace(else_range, then_node.text());
+            edit.replace(then_range, else_node.text());
+        })
+
+    } else {
+        None
+    }
+
+
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use crate::helpers::{check_assist, check_assist_not_applicable};
+
+    #[test]
+    fn invert_if_remove_inequality() {
+        check_assist(invert_if, "fn f() { i<|>f x != 3 {1} else {3 + 2} }", "fn f() { i<|>f x == 3 {3 + 2} else {1} }")
+    }
+
+    #[test]
+    fn invert_if_remove_not() {
+        check_assist(invert_if, "fn f() { <|>if !cond {3 * 2} else {1} }", "fn f() { <|>if cond {1} else {3 * 2} }")
+    }
+
+    #[test]
+    fn invert_if_doesnt_apply_with_cursor_not_on_if() {
+        check_assist_not_applicable(invert_if, "fn f() { if !<|>cond {3 * 2} else {1} }")
+    }
+
+    #[test]
+    fn invert_if_doesnt_apply_without_negated() {
+        check_assist_not_applicable(invert_if, "fn f() { i<|>f cond {3 * 2} else {1} }")
+    }
+}
index 176761efb954401484207ef1754e08f89e71ae81..1ccc016d32fe57c469ab2e34519923243f8632bc 100644 (file)
@@ -341,6 +341,23 @@ fn main() {
     )
 }
 
+#[test]
+fn doctest_invert_if() {
+    check(
+        "invert_if",
+        r#####"
+fn main() {
+    if<|> !y {A} else {B}
+}
+"#####,
+        r#####"
+fn main() {
+    if y {B} else {A}
+}
+"#####,
+    )
+}
+
 #[test]
 fn doctest_make_raw_string() {
     check(
index f2f0dacbf7d997d27003b113eb75eada55931af9..a372bd8b9d54ea9695c47b00144c84369253e2af 100644 (file)
@@ -97,6 +97,7 @@ mod assists {
     mod add_impl;
     mod add_new;
     mod apply_demorgan;
+    mod invert_if;
     mod flip_comma;
     mod flip_binexpr;
     mod flip_trait_bound;
@@ -122,6 +123,7 @@ pub(crate) fn all<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<As
             add_impl::add_impl,
             add_new::add_new,
             apply_demorgan::apply_demorgan,
+            invert_if::invert_if,
             change_visibility::change_visibility,
             fill_match_arms::fill_match_arms,
             merge_match_arms::merge_match_arms,
index 8da7578e2f2b9712a1f6e5b683d48900f7469750..6e7811bd6c058db46a2a9e266c3ef199735f1ea3 100644 (file)
@@ -329,6 +329,25 @@ fn main() {
 }
 ```
 
+## `invert_if`
+
+Apply invert_if
+This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
+This also works with `!=`. This assist can only be applied with the cursor
+on `if`.
+
+```rust
+// BEFORE
+fn main() {
+    if┃ !y {A} else {B}
+}
+
+// AFTER
+fn main() {
+    if y {B} else {A}
+}
+```
+
 ## `make_raw_string`
 
 Adds `r#` to a plain string literal.