1
1
use syntax:: ast:: { self , AstNode } ;
2
+ use test_utils:: mark;
2
3
3
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
44
"Apply De Morgan's law" ,
44
45
op_range,
45
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
61
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
+ }
49
77
} ,
50
78
)
51
79
}
@@ -62,6 +90,7 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> {
62
90
#[ cfg( test) ]
63
91
mod tests {
64
92
use ide_db:: helpers:: FamousDefs ;
93
+ use test_utils:: mark;
65
94
66
95
use super :: * ;
67
96
@@ -156,4 +185,16 @@ fn f() {
156
185
fn demorgan_doesnt_apply_with_cursor_not_on_op ( ) {
157
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
}
0 commit comments