diff options
Diffstat (limited to 'crates/ide_assists')
-rw-r--r-- | crates/ide_assists/src/handlers/apply_demorgan.rs | 45 |
1 files changed, 43 insertions, 2 deletions
diff --git a/crates/ide_assists/src/handlers/apply_demorgan.rs b/crates/ide_assists/src/handlers/apply_demorgan.rs index 6997ea048..128b1eb56 100644 --- a/crates/ide_assists/src/handlers/apply_demorgan.rs +++ b/crates/ide_assists/src/handlers/apply_demorgan.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use syntax::ast::{self, AstNode}; | 1 | use syntax::ast::{self, AstNode}; |
2 | use test_utils::mark; | ||
2 | 3 | ||
3 | use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; | 4 | use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists}; |
4 | 5 | ||
@@ -43,9 +44,36 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext) -> Option<( | |||
43 | "Apply De Morgan's law", | 44 | "Apply De Morgan's law", |
44 | op_range, | 45 | op_range, |
45 | |edit| { | 46 | |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 | |||
46 | edit.replace(op_range, opposite_op); | 61 | edit.replace(op_range, opposite_op); |
47 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); | 62 | |
48 | edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); | 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 | } | ||
49 | }, | 77 | }, |
50 | ) | 78 | ) |
51 | } | 79 | } |
@@ -62,6 +90,7 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> { | |||
62 | #[cfg(test)] | 90 | #[cfg(test)] |
63 | mod tests { | 91 | mod tests { |
64 | use ide_db::helpers::FamousDefs; | 92 | use ide_db::helpers::FamousDefs; |
93 | use test_utils::mark; | ||
65 | 94 | ||
66 | use super::*; | 95 | use super::*; |
67 | 96 | ||
@@ -156,4 +185,16 @@ fn f() { | |||
156 | fn demorgan_doesnt_apply_with_cursor_not_on_op() { | 185 | fn demorgan_doesnt_apply_with_cursor_not_on_op() { |
157 | check_assist_not_applicable(apply_demorgan, "fn f() { $0 !x || !x }") | 186 | check_assist_not_applicable(apply_demorgan, "fn f() { $0 !x || !x }") |
158 | } | 187 | } |
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 | } | ||
159 | } | 200 | } |