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 1c60f2692a0..22092471649 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 @@ -445,19 +445,24 @@ private boolean canSimplifyDoubleNegation(Expression innerExpression) { } /** - * Override this method to disable simplification of equals expressions, - * specifically for Kotlin while that is not yet part of the OpenRewrite/rewrite. + * Determines whether an equals comparison with a boolean literal can be simplified. *
- * Comparing Kotlin nullable type `?` with tree/false can not be simplified, - * e.g. `X?.fun() == true` is not equivalent to `X?.fun()` + * In Java, {@code x == true} can always be simplified to {@code x}. + * In Kotlin and other languages, nullable types like {@code Boolean?} compared + * with {@code == true} have different semantics than using the value directly, + * e.g. {@code nullableBoolean == true} evaluates to {@code false} when null, + * whereas using {@code nullableBoolean} directly would be a type error. *
- * Subclasses will want to check if the `org.openrewrite.kotlin.marker.IsNullSafe` - * marker is present. + * For non-Java languages, simplification is only allowed when the expression + * type is primitive boolean (non-nullable). * * @param j the expression to simplify - * @return true by default, unless overridden + * @return true if the equals comparison can be safely simplified */ protected boolean shouldSimplifyEqualsOn(J j) { - return true; + if (getCursor().firstEnclosing(SourceFile.class) instanceof J.CompilationUnit) { + return true; + } + return j instanceof Expression && ((Expression) j).getType() == JavaType.Primitive.Boolean; } } diff --git a/rewrite-kotlin/src/test/java/org/openrewrite/kotlin/cleanup/SimplifyBooleanExpressionVisitorTest.java b/rewrite-kotlin/src/test/java/org/openrewrite/kotlin/cleanup/SimplifyBooleanExpressionVisitorTest.java new file mode 100644 index 00000000000..102f8600c20 --- /dev/null +++ b/rewrite-kotlin/src/test/java/org/openrewrite/kotlin/cleanup/SimplifyBooleanExpressionVisitorTest.java @@ -0,0 +1,111 @@ +/* + * Copyright 2026 the original author or authors. + *
+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * https://www.apache.org/licenses/LICENSE-2.0 + *
+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.kotlin.cleanup; + +import org.junit.jupiter.api.Test; +import org.openrewrite.Issue; +import org.openrewrite.java.cleanup.SimplifyBooleanExpressionVisitor; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.kotlin.Assertions.kotlin; +import static org.openrewrite.test.RewriteTest.toRecipe; + +class SimplifyBooleanExpressionVisitorTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(toRecipe(() -> new SimplifyBooleanExpressionVisitor())); + } + + @Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/303") + @Test + void nullableReceiverEqualsTrue() { + rewriteRun( + kotlin( + """ + fun Boolean?.toLegacyFlag() = if (this == true) "1" else "0" + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/303") + @Test + void nullableVariableEqualsTrue() { + rewriteRun( + kotlin( + """ + data class Todo(val completed: Boolean?) + fun main() { + val todo = Todo(null) + val isCompleted: Boolean = todo.completed == true + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/303") + @Test + void nullableVariableEqualsFalse() { + rewriteRun( + kotlin( + """ + fun check(b: Boolean?) { + if (b == false) println("false or null") + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/303") + @Test + void nullableVariableNotEqualTrue() { + rewriteRun( + kotlin( + """ + fun check(b: Boolean?) { + if (b != true) println("not true") + } + """ + ) + ); + } + + @Test + void simplifyBooleanLiteralOperations() { + rewriteRun( + kotlin( + """ + fun check(b: Boolean) { + val a = !false + val c = b || true + val d = b && false + } + """, + """ + fun check(b: Boolean) { + val a = true + val c = true + val d = false + } + """ + ) + ); + } +}