From 965b8175fd6e12adf33c2451e8fe72b7fdb2ce16 Mon Sep 17 00:00:00 2001 From: Adriano Machado <60320+ammachado@users.noreply.github.com> Date: Mon, 8 Jan 2024 06:02:17 -0500 Subject: [PATCH] Simplify Ternary expressions [#203] (#231) * Simplify Ternary expressions [#203] * Demonstrate shortcoming with test & partial fix * Update expectations following change in rewrite * Add additional test cases; last of which fails currently * Now expect unwrapped inverted boolean method * Split tests between changed and unchanged * Apply suggestions from code review --------- Co-authored-by: Tim te Beek Co-authored-by: Tim te Beek --- build.gradle.kts | 6 + .../staticanalysis/SimplifyTernary.java | 57 ++++++++++ .../rewrite/common-static-analysis.yml | 1 + .../staticanalysis/SimplifyTernaryTest.java | 106 ++++++++++++++++++ 4 files changed, 170 insertions(+) create mode 100644 src/main/java/org/openrewrite/staticanalysis/SimplifyTernary.java create mode 100644 src/test/java/org/openrewrite/staticanalysis/SimplifyTernaryTest.java diff --git a/build.gradle.kts b/build.gradle.kts index de1b9168c..b430f94f5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,6 +20,12 @@ dependencies { implementation("org.openrewrite.meta:rewrite-analysis:${rewriteVersion}") implementation("org.apache.commons:commons-text:latest.release") + annotationProcessor("org.openrewrite:rewrite-templating:${rewriteVersion}") + implementation("org.openrewrite:rewrite-templating:${rewriteVersion}") + compileOnly("com.google.errorprone:error_prone_core:2.19.1:with-dependencies") { + exclude("com.google.auto.service", "auto-service-annotations") + } + testImplementation("org.jetbrains:annotations:24.+") testImplementation("org.openrewrite:rewrite-groovy") testImplementation("org.junit-pioneer:junit-pioneer:2.0.1") diff --git a/src/main/java/org/openrewrite/staticanalysis/SimplifyTernary.java b/src/main/java/org/openrewrite/staticanalysis/SimplifyTernary.java new file mode 100644 index 000000000..a9871b867 --- /dev/null +++ b/src/main/java/org/openrewrite/staticanalysis/SimplifyTernary.java @@ -0,0 +1,57 @@ +/* + * Copyright 2024 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.staticanalysis; + +import com.google.errorprone.refaster.annotation.AfterTemplate; +import com.google.errorprone.refaster.annotation.BeforeTemplate; +import org.openrewrite.java.template.RecipeDescriptor; + +public class SimplifyTernary { + + @RecipeDescriptor( + name = "Simplify ternary expressions", + description = "Simplify `expr ? true : false` to `expr`." + ) + public static class SimplifyTernaryTrueFalse { + + @BeforeTemplate + boolean before(boolean expr) { + return expr ? true : false; + } + + @AfterTemplate + boolean after(boolean expr) { + return expr; + } + } + + @RecipeDescriptor( + name = "Simplify ternary expressions", + description = "Simplify `expr ? false : true` to `!expr`." + ) + public static class SimplifyTernaryFalseTrue { + + @BeforeTemplate + boolean before(boolean expr) { + return expr ? false : true; + } + + @AfterTemplate + boolean after(boolean expr) { + return !(expr); + } + } +} diff --git a/src/main/resources/META-INF/rewrite/common-static-analysis.yml b/src/main/resources/META-INF/rewrite/common-static-analysis.yml index 2d31ecf0e..415541fbc 100644 --- a/src/main/resources/META-INF/rewrite/common-static-analysis.yml +++ b/src/main/resources/META-INF/rewrite/common-static-analysis.yml @@ -75,6 +75,7 @@ recipeList: - org.openrewrite.staticanalysis.ReplaceStringBuilderWithString - org.openrewrite.staticanalysis.SimplifyBooleanExpression - org.openrewrite.staticanalysis.SimplifyBooleanReturn + - org.openrewrite.staticanalysis.SimplifyTernaryRecipes - org.openrewrite.staticanalysis.StaticMethodNotFinal - org.openrewrite.staticanalysis.StringLiteralEquality - org.openrewrite.staticanalysis.UnnecessaryCloseInTryWithResources diff --git a/src/test/java/org/openrewrite/staticanalysis/SimplifyTernaryTest.java b/src/test/java/org/openrewrite/staticanalysis/SimplifyTernaryTest.java new file mode 100644 index 000000000..30dbe58dc --- /dev/null +++ b/src/test/java/org/openrewrite/staticanalysis/SimplifyTernaryTest.java @@ -0,0 +1,106 @@ +/* + * Copyright 2024 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.staticanalysis; + +import org.junit.jupiter.api.Test; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class SimplifyTernaryTest implements RewriteTest { + @Test + void simplified() { + rewriteRun( + spec -> spec.recipe(new SimplifyTernaryRecipes()), + //language=java + java( + """ + class Test { + boolean trueCondition1 = true ? true : false; + boolean trueCondition2 = false ? false : true; + boolean trueCondition3 = booleanExpression() ? true : false; + boolean trueCondition4 = trueCondition1 && trueCondition2 ? true : false; + boolean trueCondition5 = !true ? false : true; + boolean trueCondition6 = !false ? true : false; + + boolean falseCondition1 = true ? false : true; + boolean falseCondition2 = !false ? false : true; + boolean falseCondition3 = booleanExpression() ? false : true; + boolean falseCondition4 = trueCondition1 && trueCondition2 ? false : true; + boolean falseCondition5 = !false ? false : true; + boolean falseCondition6 = !true ? true : false; + + boolean binary1 = booleanExpression() && booleanExpression() ? true : false; + boolean binary2 = booleanExpression() && booleanExpression() ? false : true; + boolean binary3 = booleanExpression() || booleanExpression() ? true : false; + boolean binary4 = booleanExpression() || booleanExpression() ? false : true; + + boolean booleanExpression() { + return true; + } + } + """, + """ + class Test { + boolean trueCondition1 = true; + boolean trueCondition2 = true; + boolean trueCondition3 = booleanExpression(); + boolean trueCondition4 = trueCondition1 && trueCondition2; + boolean trueCondition5 = true; + boolean trueCondition6 = true; + + boolean falseCondition1 = false; + boolean falseCondition2 = false; + boolean falseCondition3 = !booleanExpression(); + boolean falseCondition4 = !(trueCondition1 && trueCondition2); + boolean falseCondition5 = false; + boolean falseCondition6 = false; + + boolean binary1 = booleanExpression() && booleanExpression(); + boolean binary2 = !(booleanExpression() && booleanExpression()); + boolean binary3 = booleanExpression() || booleanExpression(); + boolean binary4 = !(booleanExpression() || booleanExpression()); + + boolean booleanExpression() { + return true; + } + } + """ + ) + ); + } + + @Test + void unchanged() { + rewriteRun( + spec -> spec.recipe(new SimplifyTernaryRecipes()), + //language=java + java( + """ + class Test { + boolean unchanged1 = booleanExpression() ? booleanExpression() : !booleanExpression(); + boolean unchanged2 = booleanExpression() ? true : !booleanExpression(); + boolean unchanged3 = booleanExpression() ? booleanExpression() : false; + + boolean booleanExpression() { + return true; + } + } + """ + ) + ); + } +} \ No newline at end of file