diff --git a/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java b/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java index 0829d278da2..4888697b3ed 100644 --- a/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java +++ b/rewrite-java-test/src/test/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitorTest.java @@ -123,6 +123,62 @@ public class A { ); } + @Test + void doubleNegationWithParentheses() { + rewriteRun( + java( + """ + public class A { + { + boolean a = !!(!(!true)); + boolean b = !(!a); + } + } + """, + """ + public class A { + { + boolean a = true; + boolean b = a; + } + } + """ + ) + ); + } + + @Test + void doubleNegatedBinaryWithParentheses() { + rewriteRun( + java( + """ + public class A { + { + boolean a1 = !(1 == 1); + boolean a2 = !(1 != 1); + boolean a3 = !(1 < 1); + boolean a4 = !(1 <= 1); + boolean a5 = !(1 > 1); + boolean a6 = !(1 >= 1); + } + } + """, + """ + public class A { + { + boolean a1 = 1 != 1; + boolean a2 = 1 == 1; + boolean a3 = 1 >= 1; + boolean a4 = 1 > 1; + boolean a5 = 1 <= 1; + boolean a6 = 1 < 1; + } + } + """ + ) + ); + } + @Test void simplifyEqualsLiteralTrue() { rewriteRun( diff --git a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java index bbfb51e0752..11af27c4f31 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/cleanup/SimplifyBooleanExpressionVisitor.java @@ -108,7 +108,7 @@ public J visitBinary(J.Binary binary, ExecutionContext ctx) { @Override public J postVisit(J tree, ExecutionContext ctx) { - J j = super.postVisit(tree, ctx); + J j = tree; if (j instanceof J.Parentheses) { j = new UnwrapParentheses<>((J.Parentheses>) j).visit(j, ctx, getCursor().getParentOrThrow()); } @@ -124,12 +124,19 @@ public J visitUnary(J.Unary unary, ExecutionContext ctx) { J.Unary asUnary = (J.Unary) j; if (asUnary.getOperator() == J.Unary.Type.Not) { - if (isLiteralTrue(asUnary.getExpression())) { - j = ((J.Literal) asUnary.getExpression()).withValue(false).withValueSource("false"); - } else if (isLiteralFalse(asUnary.getExpression())) { - j = ((J.Literal) asUnary.getExpression()).withValue(true).withValueSource("true"); - } else if (asUnary.getExpression() instanceof J.Unary && ((J.Unary) asUnary.getExpression()).getOperator() == J.Unary.Type.Not) { - j = ((J.Unary) asUnary.getExpression()).getExpression(); + Expression expr = asUnary.getExpression(); + if (isLiteralTrue(expr)) { + j = ((J.Literal) expr).withValue(false).withValueSource("false"); + } else if (isLiteralFalse(expr)) { + j = ((J.Literal) expr).withValue(true).withValueSource("true"); + } else if (expr instanceof J.Unary && ((J.Unary) expr).getOperator() == J.Unary.Type.Not) { + j = ((J.Unary) expr).getExpression(); + } else if (expr instanceof J.Parentheses && ((J.Parentheses>) expr).getTree() instanceof J.Binary) { + J.Binary binary = (J.Binary) ((J.Parentheses>) expr).getTree(); + J.Binary.Type negated = negate(binary.getOperator()); + if (negated != binary.getOperator()) { + j = binary.withOperator(negated); + } } } if (asUnary != j) { @@ -138,6 +145,25 @@ public J visitUnary(J.Unary unary, ExecutionContext ctx) { return j; } + private J.Binary.Type negate(J.Binary.Type operator) { + switch (operator) { + case LessThan: + return J.Binary.Type.GreaterThanOrEqual; + case GreaterThan: + return J.Binary.Type.LessThanOrEqual; + case LessThanOrEqual: + return J.Binary.Type.GreaterThan; + case GreaterThanOrEqual: + return J.Binary.Type.LessThan; + case Equal: + return J.Binary.Type.NotEqual; + case NotEqual: + return J.Binary.Type.Equal; + default: + return operator; + } + } + private final MethodMatcher isEmpty = new MethodMatcher("java.lang.String isEmpty()"); @Override @@ -210,10 +236,10 @@ public Space visitSpace(Space space, Space.Location loc, Integer integer) { /** * Override this method to disable simplification of equals expressions, * specifically for Kotlin while that is not yet part of the OpenRewrite/rewrite. - * + *
* Comparing Kotlin nullable type `?` with tree/false can not be simplified, * e.g. `X?.fun() == true` is not equivalent to `X?.fun()` - * + *
* Subclasses will want to check if the `org.openrewrite.kotlin.marker.IsNullSafe` * marker is present. *