From 8a8be062194604360bbb27ee11961b8a72973f44 Mon Sep 17 00:00:00 2001 From: bravomikekilo Date: Fri, 22 Nov 2019 02:51:40 +0800 Subject: initial invert_if --- crates/ra_assists/src/assists/apply_demorgan.rs | 2 +- crates/ra_assists/src/assists/invert_if.rs | 85 +++++++++++++++++++++++++ crates/ra_assists/src/doc_tests/generated.rs | 17 +++++ crates/ra_assists/src/lib.rs | 2 + 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 crates/ra_assists/src/assists/invert_if.rs (limited to 'crates/ra_assists') 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> { } // This function tries to undo unary negation, or inequality -fn undo_negation(node: SyntaxNode) -> Option { +pub(crate) fn undo_negation(node: SyntaxNode) -> Option { 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 index 000000000..9a53a3d18 --- /dev/null +++ b/crates/ra_assists/src/assists/invert_if.rs @@ -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) -> Option { + let expr = ctx.find_node_at_offset::()?; + 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} }") + } +} 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 @@ -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( 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 { 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 @@ mod assists { 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, -- cgit v1.2.3 From 1ebfa908d50a7ef4765d2abb432531d9c98cbb58 Mon Sep 17 00:00:00 2001 From: bravomikekilo Date: Fri, 22 Nov 2019 03:18:22 +0800 Subject: fix tidy test --- crates/ra_assists/src/assists/invert_if.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'crates/ra_assists') diff --git a/crates/ra_assists/src/assists/invert_if.rs b/crates/ra_assists/src/assists/invert_if.rs index 9a53a3d18..c2c8529fe 100644 --- a/crates/ra_assists/src/assists/invert_if.rs +++ b/crates/ra_assists/src/assists/invert_if.rs @@ -2,8 +2,8 @@ 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; +use crate::{Assist, AssistCtx, AssistId}; // Assist: invert_if // @@ -24,7 +24,6 @@ use super::apply_demorgan::undo_negation; // } // ``` - pub(crate) fn invert_if(ctx: AssistCtx) -> Option { let expr = ctx.find_node_at_offset::()?; let expr_range = expr.syntax().text_range(); @@ -49,12 +48,9 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option { edit.replace(else_range, then_node.text()); edit.replace(then_range, else_node.text()); }) - } else { None } - - } #[cfg(test)] @@ -65,12 +61,20 @@ mod tests { #[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} }") + 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} }") + check_assist( + invert_if, + "fn f() { <|>if !cond {3 * 2} else {1} }", + "fn f() { <|>if cond {1} else {3 * 2} }", + ) } #[test] -- cgit v1.2.3 From d8caf56dfc9eb3cdddff05b58b954a78cf1b9476 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 22 Nov 2019 21:52:06 +0300 Subject: Uniformalize naming --- crates/ra_assists/src/assists/add_new.rs | 2 +- crates/ra_assists/src/assists/fill_match_arms.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'crates/ra_assists') diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs index b5f8afb4e..ee8bff346 100644 --- a/crates/ra_assists/src/assists/add_new.rs +++ b/crates/ra_assists/src/assists/add_new.rs @@ -36,7 +36,7 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option { // We want to only apply this to non-union structs with named fields let field_list = match (strukt.kind(), strukt.is_union()) { - (StructKind::Named(named), false) => named, + (StructKind::Record(named), false) => named, _ => return None, }; diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs index 9354466d9..8482897c5 100644 --- a/crates/ra_assists/src/assists/fill_match_arms.rs +++ b/crates/ra_assists/src/assists/fill_match_arms.rs @@ -101,7 +101,7 @@ fn build_pat(var: ast::EnumVariant) -> Option { iter::repeat(make::placeholder_pat().into()).take(field_list.fields().count()); make::tuple_struct_pat(path, pats).into() } - ast::StructKind::Named(field_list) => { + ast::StructKind::Record(field_list) => { let pats = field_list.fields().map(|f| make::bind_pat(f.name().unwrap()).into()); make::record_pat(path, pats).into() } -- cgit v1.2.3 From 958862093e83083b188427246323047a2c9e7bab Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 23 Nov 2019 14:43:38 +0300 Subject: Move docs to hir_def --- crates/ra_assists/src/test_db.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'crates/ra_assists') diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs index 5be7383ed..715270344 100644 --- a/crates/ra_assists/src/test_db.rs +++ b/crates/ra_assists/src/test_db.rs @@ -9,7 +9,6 @@ use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath ra_db::SourceDatabaseStorage, hir::db::InternDatabaseStorage, hir::db::AstDatabaseStorage, - hir::db::DefDatabaseStorage, hir::db::DefDatabase2Storage, hir::db::HirDatabaseStorage )] -- cgit v1.2.3 From fc1e543f7abb69b8cab308410fa0a127950ee1c5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 23 Nov 2019 14:44:43 +0300 Subject: Get rid of DefDatabase2 --- crates/ra_assists/src/test_db.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_assists') diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs index 715270344..5f96c974b 100644 --- a/crates/ra_assists/src/test_db.rs +++ b/crates/ra_assists/src/test_db.rs @@ -9,7 +9,7 @@ use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath ra_db::SourceDatabaseStorage, hir::db::InternDatabaseStorage, hir::db::AstDatabaseStorage, - hir::db::DefDatabase2Storage, + hir::db::DefDatabaseStorage, hir::db::HirDatabaseStorage )] #[derive(Debug, Default)] -- cgit v1.2.3 From adac4fc2f21117486356063d82d79f8c3add084a Mon Sep 17 00:00:00 2001 From: bravomikekilo Date: Sun, 24 Nov 2019 13:14:57 +0800 Subject: do refact and fix some issue --- crates/ra_assists/src/assists/apply_demorgan.rs | 40 ++++-------------- crates/ra_assists/src/assists/invert_if.rs | 55 +++++++++++++++---------- crates/ra_assists/src/doc_tests/generated.rs | 4 +- 3 files changed, 45 insertions(+), 54 deletions(-) (limited to 'crates/ra_assists') diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs index 0d59a0d24..7c57c0560 100644 --- a/crates/ra_assists/src/assists/apply_demorgan.rs +++ b/crates/ra_assists/src/assists/apply_demorgan.rs @@ -1,6 +1,6 @@ +use super::invert_if::invert_boolean_expression; use hir::db::HirDatabase; use ra_syntax::ast::{self, AstNode}; -use ra_syntax::SyntaxNode; use crate::{Assist, AssistCtx, AssistId}; @@ -32,18 +32,18 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option if !cursor_in_range { return None; } - let lhs = expr.lhs()?.syntax().clone(); - let lhs_range = lhs.text_range(); - let rhs = expr.rhs()?.syntax().clone(); - let rhs_range = rhs.text_range(); - let not_lhs = undo_negation(lhs)?; - let not_rhs = undo_negation(rhs)?; + let lhs = expr.lhs()?; + let lhs_range = lhs.syntax().text_range(); + let rhs = expr.rhs()?; + let rhs_range = rhs.syntax().text_range(); + let not_lhs = invert_boolean_expression(&lhs)?; + let not_rhs = invert_boolean_expression(&rhs)?; ctx.add_assist(AssistId("apply_demorgan"), "apply demorgan's law", |edit| { edit.target(op_range); edit.replace(op_range, opposite_op); - edit.replace(lhs_range, format!("!({}", not_lhs)); - edit.replace(rhs_range, format!("{})", not_rhs)); + edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); + edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); }) } @@ -56,28 +56,6 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> { } } -// This function tries to undo unary negation, or inequality -pub(crate) fn undo_negation(node: SyntaxNode) -> Option { - match ast::Expr::cast(node)? { - ast::Expr::BinExpr(bin) => match bin.op_kind()? { - ast::BinOp::NegatedEqualityTest => { - let lhs = bin.lhs()?.syntax().text(); - let rhs = bin.rhs()?.syntax().text(); - Some(format!("{} == {}", lhs, rhs)) - } - _ => None, - }, - ast::Expr::PrefixExpr(pe) => match pe.op_kind()? { - ast::PrefixOp::Not => { - let child = pe.expr()?.syntax().text(); - Some(String::from(child)) - } - _ => None, - }, - _ => None, - } -} - #[cfg(test)] mod tests { use super::*; 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 @@ use hir::db::HirDatabase; use ra_syntax::ast::{self, AstNode}; -use ra_syntax::{TextRange, TextUnit}; +use ra_syntax::T; -use super::apply_demorgan::undo_negation; use crate::{Assist, AssistCtx, AssistId}; // Assist: invert_if @@ -14,42 +13,56 @@ use crate::{Assist, AssistCtx, AssistId}; // // ``` // fn main() { -// if<|> !y {A} else {B} +// if<|> !y { A } else { B } // } // ``` // -> // ``` // fn main() { -// if y {B} else {A} +// if y { B } else { A } // } // ``` pub(crate) fn invert_if(ctx: AssistCtx) -> Option { - let expr = ctx.find_node_at_offset::()?; - let expr_range = expr.syntax().text_range(); - let if_range = TextRange::offset_len(expr_range.start(), TextUnit::from_usize(2)); + let if_keyword = ctx.find_token_at_offset(T![if])?; + let expr = ast::IfExpr::cast(if_keyword.parent())?; + let if_range = if_keyword.text_range(); 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 cond = expr.condition()?.expr()?; 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 flip_cond = invert_boolean_expression(&cond)?; + let cond_range = cond.syntax().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| { + return ctx.add_assist(AssistId("invert_if"), "invert if branches", |edit| { edit.target(if_range); - edit.replace(cond_range, flip_cond); + edit.replace(cond_range, flip_cond.syntax().text()); edit.replace(else_range, then_node.text()); edit.replace(then_range, else_node.text()); - }) - } else { - None + }); + } + + None +} + +pub(crate) fn invert_boolean_expression(expr: &ast::Expr) -> Option { + match expr { + ast::Expr::BinExpr(bin) => match bin.op_kind()? { + ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()), + _ => None, + }, + ast::Expr::PrefixExpr(pe) => match pe.op_kind()? { + ast::PrefixOp::Not => pe.expr(), + _ => None, + }, + _ => None, } } @@ -63,8 +76,8 @@ mod tests { 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} }", + "fn f() { i<|>f x != 3 { 1 } else { 3 + 2 } }", + "fn f() { i<|>f x == 3 { 3 + 2 } else { 1 } }", ) } @@ -72,18 +85,18 @@ mod tests { 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} }", + "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} }") + 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} }") + check_assist_not_applicable(invert_if, "fn f() { i<|>f cond { 3 * 2 } else { 1 } }") } } diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index 1ccc016d3..3c716c2d1 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs @@ -347,12 +347,12 @@ fn doctest_invert_if() { "invert_if", r#####" fn main() { - if<|> !y {A} else {B} + if<|> !y { A } else { B } } "#####, r#####" fn main() { - if y {B} else {A} + if y { B } else { A } } "#####, ) -- cgit v1.2.3