Skip to content

Commit 1363d60

Browse files
committed
Special-case parenthesized and negated expressions in demorgan assist
1 parent 2b22fc9 commit 1363d60

File tree

1 file changed

+43
-2
lines changed

1 file changed

+43
-2
lines changed

crates/ide_assists/src/handlers/apply_demorgan.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use syntax::ast::{self, AstNode};
2+
use test_utils::mark;
23

34
use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
45

@@ -43,9 +44,36 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<(
4344
"Apply De Morgan's law",
4445
op_range,
4546
|edit| {
47+
let paren_expr = expr.syntax().parent().and_then(|parent| ast::ParenExpr::cast(parent));
48+
49+
let neg_expr = paren_expr
50+
.clone()
51+
.and_then(|paren_expr| paren_expr.syntax().parent())
52+
.and_then(|parent| ast::PrefixExpr::cast(parent))
53+
.and_then(|prefix_expr| {
54+
if prefix_expr.op_kind().unwrap() == ast::PrefixOp::Not {
55+
Some(prefix_expr)
56+
} else {
57+
None
58+
}
59+
});
60+
4661
edit.replace(op_range, opposite_op);
47-
edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
48-
edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
62+
63+
if let Some(paren_expr) = paren_expr {
64+
edit.replace(lhs_range, not_lhs.syntax().text());
65+
edit.replace(rhs_range, not_rhs.syntax().text());
66+
if let Some(neg_expr) = neg_expr {
67+
mark::hit!(demorgan_double_negation);
68+
edit.replace(neg_expr.op_token().unwrap().text_range(), "");
69+
} else {
70+
mark::hit!(demorgan_double_parens);
71+
edit.replace(paren_expr.l_paren_token().unwrap().text_range(), "!(");
72+
}
73+
} else {
74+
edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
75+
edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
76+
}
4977
},
5078
)
5179
}
@@ -62,6 +90,7 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
6290
#[cfg(test)]
6391
mod tests {
6492
use ide_db::helpers::FamousDefs;
93+
use test_utils::mark;
6594

6695
use super::*;
6796

@@ -156,4 +185,16 @@ fn f() {
156185
fn demorgan_doesnt_apply_with_cursor_not_on_op() {
157186
check_assist_not_applicable(apply_demorgan, "fn f() { $0 !x || !x }")
158187
}
188+
189+
#[test]
190+
fn demorgan_doesnt_double_negation() {
191+
mark::check!(demorgan_double_negation);
192+
check_assist(apply_demorgan, "fn f() { !(x ||$0 x) }", "fn f() { (!x && !x) }")
193+
}
194+
195+
#[test]
196+
fn demorgan_doesnt_double_parens() {
197+
mark::check!(demorgan_double_parens);
198+
check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }")
199+
}
159200
}

0 commit comments

Comments
 (0)