mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-29 13:25:09 +00:00
Generalize invert_if to just always work
This commit is contained in:
parent
5aba5a756a
commit
aa1234e02b
3 changed files with 35 additions and 18 deletions
|
@ -31,12 +31,14 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> {
|
||||||
if !cursor_in_range {
|
if !cursor_in_range {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lhs = expr.lhs()?;
|
let lhs = expr.lhs()?;
|
||||||
let lhs_range = lhs.syntax().text_range();
|
let lhs_range = lhs.syntax().text_range();
|
||||||
|
let not_lhs = invert_boolean_expression(lhs);
|
||||||
|
|
||||||
let rhs = expr.rhs()?;
|
let rhs = expr.rhs()?;
|
||||||
let rhs_range = rhs.syntax().text_range();
|
let rhs_range = rhs.syntax().text_range();
|
||||||
let not_lhs = invert_boolean_expression(&lhs)?;
|
let not_rhs = invert_boolean_expression(rhs);
|
||||||
let not_rhs = invert_boolean_expression(&rhs)?;
|
|
||||||
|
|
||||||
ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", |edit| {
|
ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", |edit| {
|
||||||
edit.target(op_range);
|
edit.target(op_range);
|
||||||
|
@ -77,12 +79,12 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn demorgan_doesnt_apply_with_cursor_not_on_op() {
|
fn demorgan_general_case() {
|
||||||
check_assist_not_applicable(apply_demorgan, "fn f() { <|> !x || !x }")
|
check_assist(apply_demorgan, "fn f() { x ||<|> x }", "fn f() { !(!x &&<|> !x) }")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn demorgan_doesnt_apply_when_operands_arent_negated_already() {
|
fn demorgan_doesnt_apply_with_cursor_not_on_op() {
|
||||||
check_assist_not_applicable(apply_demorgan, "fn f() { x ||<|> x }")
|
check_assist_not_applicable(apply_demorgan, "fn f() { <|> !x || !x }")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use ra_syntax::ast::{self, AstNode};
|
use ra_syntax::ast::{self, make, AstNode};
|
||||||
use ra_syntax::T;
|
use ra_syntax::T;
|
||||||
|
|
||||||
use crate::{Assist, AssistCtx, AssistId};
|
use crate::{Assist, AssistCtx, AssistId};
|
||||||
|
@ -35,8 +35,8 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
|
||||||
let then_node = expr.then_branch()?.syntax().clone();
|
let then_node = expr.then_branch()?.syntax().clone();
|
||||||
|
|
||||||
if let ast::ElseBranch::Block(else_block) = expr.else_branch()? {
|
if let ast::ElseBranch::Block(else_block) = expr.else_branch()? {
|
||||||
let flip_cond = invert_boolean_expression(&cond)?;
|
|
||||||
let cond_range = cond.syntax().text_range();
|
let cond_range = cond.syntax().text_range();
|
||||||
|
let flip_cond = invert_boolean_expression(cond);
|
||||||
let else_node = else_block.syntax();
|
let else_node = else_block.syntax();
|
||||||
let else_range = else_node.text_range();
|
let else_range = else_node.text_range();
|
||||||
let then_range = then_node.text_range();
|
let then_range = then_node.text_range();
|
||||||
|
@ -51,16 +51,23 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn invert_boolean_expression(expr: &ast::Expr) -> Option<ast::Expr> {
|
pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
|
||||||
|
if let Some(expr) = invert_special_case(&expr) {
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
make::expr_prefix(T![!], expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
|
||||||
match expr {
|
match expr {
|
||||||
ast::Expr::BinExpr(bin) => match bin.op_kind()? {
|
ast::Expr::BinExpr(bin) => match bin.op_kind()? {
|
||||||
ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()),
|
ast::BinOp::NegatedEqualityTest => bin.replace_op(T![==]).map(|it| it.into()),
|
||||||
|
ast::BinOp::EqualityTest => bin.replace_op(T![!=]).map(|it| it.into()),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
ast::Expr::PrefixExpr(pe) => match pe.op_kind()? {
|
ast::Expr::PrefixExpr(pe) if pe.op_kind()? == ast::PrefixOp::Not => pe.expr(),
|
||||||
ast::PrefixOp::Not => pe.expr(),
|
// FIXME:
|
||||||
_ => None,
|
// ast::Expr::Literal(true | false )
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,12 +97,16 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invert_if_doesnt_apply_with_cursor_not_on_if() {
|
fn invert_if_general_case() {
|
||||||
check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }")
|
check_assist(
|
||||||
|
invert_if,
|
||||||
|
"fn f() { i<|>f cond { 3 * 2 } else { 1 } }",
|
||||||
|
"fn f() { i<|>f !cond { 1 } else { 3 * 2 } }",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn invert_if_doesnt_apply_without_negated() {
|
fn invert_if_doesnt_apply_with_cursor_not_on_if() {
|
||||||
check_assist_not_applicable(invert_if, "fn f() { i<|>f cond { 3 * 2 } else { 1 } }")
|
check_assist_not_applicable(invert_if, "fn f() { if !<|>cond { 3 * 2 } else { 1 } }")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,10 @@ pub fn expr_return() -> ast::Expr {
|
||||||
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
|
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
|
||||||
expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax()))
|
expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax()))
|
||||||
}
|
}
|
||||||
|
pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
|
||||||
|
let token = token(op);
|
||||||
|
expr_from_text(&format!("{}{}", token, expr.syntax()))
|
||||||
|
}
|
||||||
fn expr_from_text(text: &str) -> ast::Expr {
|
fn expr_from_text(text: &str) -> ast::Expr {
|
||||||
ast_from_text(&format!("const C: () = {};", text))
|
ast_from_text(&format!("const C: () = {};", text))
|
||||||
}
|
}
|
||||||
|
@ -203,7 +207,7 @@ pub mod tokens {
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
|
pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
|
||||||
Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2)\n;"));
|
Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;"));
|
||||||
|
|
||||||
pub fn comma() -> SyntaxToken {
|
pub fn comma() -> SyntaxToken {
|
||||||
SOURCE_FILE
|
SOURCE_FILE
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue