11use syntax:: ast:: { self , AstNode } ;
2+ use test_utils:: mark;
23
34use 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) ]
6391mod 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