From 5d6ea6209a7fcdb89331e119c7a4c50e1a6a2458 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Sat, 30 Aug 2025 10:02:44 +0200
Subject: [PATCH 01/19] Mergeable `if` statements should be combined -
RSPEC-S1066
---
.../CombineMergeableIfStatements.java | 97 ++++
.../CombineMergeableIfStatementsTest.java | 420 ++++++++++++++++++
2 files changed, 517 insertions(+)
create mode 100644 src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
create mode 100644 src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
new file mode 100644
index 000000000..bea4b46bc
--- /dev/null
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * 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.openrewrite.ExecutionContext;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.JavaTemplate;
+import org.openrewrite.java.tree.Expression;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.Statement;
+
+import java.util.List;
+import java.util.Set;
+
+import static java.util.Collections.singleton;
+import static org.openrewrite.java.format.ShiftFormat.indent;
+
+public class CombineMergeableIfStatements extends Recipe {
+ @Override
+ public String getDisplayName() {
+ // language=markdown
+ return "Mergeable `if` statements should be combined";
+ }
+
+ @Override
+ public String getDescription() {
+ // language=markdown
+ return "Mergeable `if` statements should be combined.";
+ }
+
+ @Override
+ public Set getTags() {
+ return singleton("RSPEC-S1066");
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return new JavaIsoVisitor() {
+ @Override
+ public J.If visitIf(J.If iff, ExecutionContext ctx) {
+ J.If outerIf = super.visitIf(iff, ctx);
+
+ if (outerIf.getElsePart() == null) {
+ // thenPart is either a single if or a block with a single if
+ J.Block outerBlock = null;
+ J.If innerIf = null;
+ if (outerIf.getThenPart() instanceof J.If) {
+ innerIf = (J.If) outerIf.getThenPart();
+ } else if (outerIf.getThenPart() instanceof J.Block) {
+ outerBlock = (J.Block) outerIf.getThenPart();
+ List statements = outerBlock.getStatements();
+ if (statements.size() == 1 && statements.get(0) instanceof J.If) {
+ innerIf = (J.If) statements.get(0);
+ }
+ }
+
+ if (innerIf != null && innerIf.getElsePart() == null) {
+ // thenPart of outer if is replaced with thenPart of innerIf
+ // combine conditions with logical AND : correct parenthesizing is handled by JavaTemplate
+ final Expression outerCondition = outerIf.getIfCondition().getTree();
+ final Expression innerCondition = innerIf.getIfCondition().getTree();
+
+ innerIf = indent(innerIf, getCursor(), -1);
+ outerIf = outerIf.withThenPart(innerIf.getThenPart());
+ outerIf = JavaTemplate.apply(
+ "#{any()} && #{any()}",
+ updateCursor(outerIf),
+ outerCondition.getCoordinates().replace(),
+ outerCondition,
+ innerCondition);
+ outerIf = outerIf.withComments(outerBlock != null ?
+ ListUtils.concatAll(outerBlock.getComments(), innerIf.getComments()) :
+ innerIf.getComments());
+ }
+ }
+
+ return outerIf;
+ }
+ };
+ }
+}
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
new file mode 100644
index 000000000..07615c51e
--- /dev/null
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2025 the original author or authors.
+ *
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * 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.DocumentExample;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+import static org.openrewrite.java.Assertions.version;
+
+class CombineMergeableIfStatementsTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new CombineMergeableIfStatements());
+ }
+
+ @DocumentExample
+ @Test
+ void combineMergeableIfStatements() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1 && condition2) {
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void simplifyWithPatternMatchingForInstanceOf() {
+ rewriteRun(
+ spec -> spec
+ .recipes(new InstanceOfPatternMatch(), new CombineMergeableIfStatements())
+ .allSources(sourceSpec -> version(sourceSpec, 17)),
+ // language=java
+ java(
+ """
+ class A {
+ void a(Object o) {
+ if (o instanceof String) {
+ String s = (String) o;
+ if (s.isEmpty()) {
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(Object o) {
+ if (o instanceof String s && s.isEmpty()) {
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+
+ }
+
+ @Test
+ void simplifyWithMultiplePatternMatchingForInstanceOf() {
+ // This test doesn't fully simplify but could with an 'Inline Local Variable Used Once' recipe
+ rewriteRun(
+ spec -> spec
+ .recipes(new InstanceOfPatternMatch(), new CombineMergeableIfStatements())
+ .allSources(sourceSpec -> version(sourceSpec, 17)),
+ // language=java
+ java(
+ """
+ import java.util.List;
+
+ class A {
+ void a(Object o1) {
+ if (o1 instanceof List>) {
+ List> list = (List>) o1;
+ if (!list.isEmpty()) {
+ Object o2 = list.get(0);
+ if (o2 instanceof String) {
+ String s = (String) o2;
+ if (s.isEmpty()) {
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ }
+ }
+ """,
+ """
+ import java.util.List;
+
+ class A {
+ void a(Object o1) {
+ if (o1 instanceof List> list && !list.isEmpty()) {
+ Object o2 = list.get(0);
+ if (o2 instanceof String s && s.isEmpty()) {
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void combineWithoutBlocks() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1)
+ if (condition2)
+ System.out.println("OK");
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1 && condition2)
+ System.out.println("OK");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void combineSeveralNestedIfs() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
+ if (b1) {
+ if (b2) {
+ if (b3) {
+ if (b4) {
+ if (b5) {
+ if (b6) {
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
+ if (b1 && b2 && b3 && b4 && b5 && b6) {
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenOuterIfHasElsePart() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ }
+ } else {
+ System.out.println("KO");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenOuterIfHasEmptyBlockAsElsePart() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ }
+ } else {
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenOuterIfHasEmptyStatementAsElsePart() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ }
+ } else;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenOuterIfHasOneStatementInThenPartButIsNotIf() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ System.out.println("KO");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenOuterIfHasOneStatementWithoutBlockInThenPartButIsNotIf() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1)
+ System.out.println("KO");
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenOuterIfHasTwoStatementsInThenPart() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ }
+ System.out.println("KO");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenInnerIfHasElsePart() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ } else {
+ System.out.println("KO");
+ }
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenInnerIfHasEmptyBlockAsElsePart() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ } else {
+ }
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noSimplificationWhenInnerIfHasEmptyStatementAsElsePart() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ } else;
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void combineMergeableIfStatementsWithComments() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) /* Comment 0 */ { // Comment 1
+ // Comment 2
+ if (condition2) /* Comment 3 */ { // Comment 4
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ /* Comment 0 */ // Comment 1
+ // Comment 2
+ if (condition1 && condition2) /* Comment 3 */ { // Comment 4
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+}
From 4551ac68370cf1d7cde41c13afd29edfe36461f4 Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Mon, 8 Sep 2025 18:52:45 +0200
Subject: [PATCH 02/19] Show correct handling of binary in inner condition
---
.../CombineMergeableIfStatements.java | 4 +--
.../CombineMergeableIfStatementsTest.java | 29 +++++++++++++++++++
2 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index bea4b46bc..f54d2f281 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -73,8 +73,8 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
if (innerIf != null && innerIf.getElsePart() == null) {
// thenPart of outer if is replaced with thenPart of innerIf
// combine conditions with logical AND : correct parenthesizing is handled by JavaTemplate
- final Expression outerCondition = outerIf.getIfCondition().getTree();
- final Expression innerCondition = innerIf.getIfCondition().getTree();
+ Expression outerCondition = outerIf.getIfCondition().getTree();
+ Expression innerCondition = innerIf.getIfCondition().getTree();
innerIf = indent(innerIf, getCursor(), -1);
outerIf = outerIf.withThenPart(innerIf.getThenPart());
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
index 07615c51e..bdf9f00a2 100644
--- a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -417,4 +417,33 @@ void a(boolean condition1, boolean condition2) {
)
);
}
+
+ @Test
+ void combineBinaryConditions() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2, boolean condition3) {
+ if (condition1) {
+ if (condition2 || condition3) {
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean condition1, boolean condition2, boolean condition3) {
+ if (condition1 && (condition2 || condition3)) {
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
}
From a81f9047cc93831224767284cd563380534db714 Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Mon, 8 Sep 2025 19:00:48 +0200
Subject: [PATCH 03/19] Inline repeated assignments and add early return
---
.../CombineMergeableIfStatements.java | 20 +++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index f54d2f281..e71e18694 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -77,16 +77,16 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
Expression innerCondition = innerIf.getIfCondition().getTree();
innerIf = indent(innerIf, getCursor(), -1);
- outerIf = outerIf.withThenPart(innerIf.getThenPart());
- outerIf = JavaTemplate.apply(
- "#{any()} && #{any()}",
- updateCursor(outerIf),
- outerCondition.getCoordinates().replace(),
- outerCondition,
- innerCondition);
- outerIf = outerIf.withComments(outerBlock != null ?
- ListUtils.concatAll(outerBlock.getComments(), innerIf.getComments()) :
- innerIf.getComments());
+ return JavaTemplate.apply(
+ "#{any()} && #{any()}",
+ updateCursor(outerIf),
+ outerCondition.getCoordinates().replace(),
+ outerCondition,
+ innerCondition)
+ .withThenPart(innerIf.getThenPart())
+ .withComments(outerBlock != null ?
+ ListUtils.concatAll(outerBlock.getComments(), innerIf.getComments()) :
+ innerIf.getComments());
}
}
From 48c6fbe104f4c885f3b6ed79b62ef904d3746981 Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Mon, 8 Sep 2025 19:17:00 +0200
Subject: [PATCH 04/19] Show comment lost in current iteration.
---
.../staticanalysis/CombineMergeableIfStatementsTest.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
index bdf9f00a2..b2493739c 100644
--- a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -394,6 +394,7 @@ void combineMergeableIfStatementsWithComments() {
"""
class A {
void a(boolean condition1, boolean condition2) {
+ // Comment -1
if (condition1) /* Comment 0 */ { // Comment 1
// Comment 2
if (condition2) /* Comment 3 */ { // Comment 4
@@ -406,6 +407,7 @@ void a(boolean condition1, boolean condition2) {
"""
class A {
void a(boolean condition1, boolean condition2) {
+ // Comment -1
/* Comment 0 */ // Comment 1
// Comment 2
if (condition1 && condition2) /* Comment 3 */ { // Comment 4
From 5b3388631879d79e7a00cf2b2bdec299b5e0f9af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Sat, 13 Sep 2025 11:57:21 +0200
Subject: [PATCH 05/19] Preserve comments associated with outer `if`
---
.../staticanalysis/CombineMergeableIfStatements.java | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index e71e18694..b63dccdb2 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -18,7 +18,6 @@
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
-import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.tree.Expression;
@@ -28,7 +27,9 @@
import java.util.List;
import java.util.Set;
+import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
+import static org.openrewrite.internal.ListUtils.concatAll;
import static org.openrewrite.java.format.ShiftFormat.indent;
public class CombineMergeableIfStatements extends Recipe {
@@ -79,14 +80,14 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
innerIf = indent(innerIf, getCursor(), -1);
return JavaTemplate.apply(
"#{any()} && #{any()}",
- updateCursor(outerIf),
+ getCursor(),
outerCondition.getCoordinates().replace(),
outerCondition,
innerCondition)
.withThenPart(innerIf.getThenPart())
- .withComments(outerBlock != null ?
- ListUtils.concatAll(outerBlock.getComments(), innerIf.getComments()) :
- innerIf.getComments());
+ .withComments(concatAll(
+ concatAll(outerIf.getComments(), outerBlock != null ? outerBlock.getComments() : emptyList()),
+ innerIf.getComments()));
}
}
From 002a234de44c1095b8bbc13f48b9a4c5e1be0710 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Sat, 13 Sep 2025 23:47:29 +0200
Subject: [PATCH 06/19] Move inner `if` to a new line
---
.../CombineMergeableIfStatements.java | 88 +++++++++++++++++--
.../CombineMergeableIfStatementsTest.java | 63 +++++++++++--
2 files changed, 138 insertions(+), 13 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index b63dccdb2..3f33389ee 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -15,24 +15,37 @@
*/
package org.openrewrite.staticanalysis;
+import lombok.RequiredArgsConstructor;
+import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
+import org.openrewrite.Tree;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
+import org.openrewrite.java.style.IntelliJ;
+import org.openrewrite.java.style.TabsAndIndentsStyle;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaSourceFile;
+import org.openrewrite.java.tree.Space;
import org.openrewrite.java.tree.Statement;
+import org.openrewrite.java.tree.TextComment;
+import org.openrewrite.style.Style;
import java.util.List;
import java.util.Set;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
+import static java.util.Objects.requireNonNull;
import static org.openrewrite.internal.ListUtils.concatAll;
import static org.openrewrite.java.format.ShiftFormat.indent;
public class CombineMergeableIfStatements extends Recipe {
+
+ private static final String CONTINUATION_KEY = "continuationAfterLogicalAnd";
+
@Override
public String getDisplayName() {
// language=markdown
@@ -78,12 +91,13 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
Expression innerCondition = innerIf.getIfCondition().getTree();
innerIf = indent(innerIf, getCursor(), -1);
+ doAfterVisit(new MergedConditionalVisitor<>());
return JavaTemplate.apply(
- "#{any()} && #{any()}",
- getCursor(),
- outerCondition.getCoordinates().replace(),
- outerCondition,
- innerCondition)
+ String.format("#{any()} /*%s*/&& #{any()}", CONTINUATION_KEY),
+ getCursor(),
+ outerCondition.getCoordinates().replace(),
+ outerCondition,
+ innerCondition)
.withThenPart(innerIf.getThenPart())
.withComments(concatAll(
concatAll(outerIf.getComments(), outerBlock != null ? outerBlock.getComments() : emptyList()),
@@ -95,4 +109,68 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
}
};
}
+
+ @RequiredArgsConstructor
+ private static class MergedConditionalVisitor extends JavaIsoVisitor
{
+ @Nullable
+ private TabsAndIndentsStyle tabsAndIndentsStyle;
+
+ @Override
+ public @Nullable J visit(@Nullable Tree tree, P p) {
+ if (tree instanceof JavaSourceFile) {
+ JavaSourceFile cu = (JavaSourceFile) requireNonNull(tree);
+ tabsAndIndentsStyle = Style.from(TabsAndIndentsStyle.class, cu, IntelliJ::tabsAndIndents);
+ }
+ return super.visit(tree, p);
+ }
+
+ @Override
+ public Space visitSpace(@Nullable Space space, Space.Location loc, P p) {
+ Space s = super.visitSpace(space, loc, p);
+ if (s.getComments().size() == 1 &&
+ s.getComments().get(0) instanceof TextComment) {
+ TextComment onlyComment = (TextComment) s.getComments().get(0);
+ if (onlyComment.isMultiline() &&
+ CONTINUATION_KEY.equals(onlyComment.getText()) &&
+ getCursor().firstEnclosingOrThrow(J.Binary.class).getOperator() == J.Binary.Type.And) {
+ getCursor().putMessageOnFirstEnclosing(J.Binary.class, CONTINUATION_KEY, true);
+ s = s.withComments(emptyList());
+ }
+ }
+
+ return s;
+ }
+
+ @Override
+ public J.Binary visitBinary(J.Binary binary, P p) {
+ J.Binary b = super.visitBinary(binary, p);
+
+ if (Boolean.TRUE.equals(getCursor().getMessage(CONTINUATION_KEY))) {
+ J.If outerIf = getCursor().firstEnclosingOrThrow(J.If.class);
+ final String outerIfIndent = outerIf.getPrefix().getIndent();
+ b = b.withRight(b.getRight().withPrefix(
+ Space.format("\n" + continuationIndent(requireNonNull(tabsAndIndentsStyle), outerIfIndent))));
+ }
+
+ return b;
+ }
+
+ private String continuationIndent(TabsAndIndentsStyle tabsAndIndents, String currentIndent) {
+ char c;
+ int len;
+ if (tabsAndIndents.getUseTabCharacter()) {
+ c = '\t';
+ len = tabsAndIndents.getContinuationIndent() / tabsAndIndents.getTabSize();
+ } else {
+ c = ' ';
+ len = tabsAndIndents.getContinuationIndent();
+ }
+
+ StringBuilder sb = new StringBuilder(currentIndent);
+ for (int i = 0; i < len; i++) {
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+ }
}
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
index b2493739c..6ece54a1c 100644
--- a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -50,7 +50,8 @@ void a(boolean condition1, boolean condition2) {
"""
class A {
void a(boolean condition1, boolean condition2) {
- if (condition1 && condition2) {
+ if (condition1 &&
+ condition2) {
System.out.println("OK");
}
}
@@ -83,7 +84,8 @@ void a(Object o) {
"""
class A {
void a(Object o) {
- if (o instanceof String s && s.isEmpty()) {
+ if (o instanceof String s &&
+ s.isEmpty()) {
System.out.println("OK");
}
}
@@ -128,9 +130,11 @@ void a(Object o1) {
class A {
void a(Object o1) {
- if (o1 instanceof List> list && !list.isEmpty()) {
+ if (o1 instanceof List> list &&
+ !list.isEmpty()) {
Object o2 = list.get(0);
- if (o2 instanceof String s && s.isEmpty()) {
+ if (o2 instanceof String s &&
+ s.isEmpty()) {
System.out.println("OK");
}
}
@@ -158,7 +162,8 @@ void a(boolean condition1, boolean condition2) {
"""
class A {
void a(boolean condition1, boolean condition2) {
- if (condition1 && condition2)
+ if (condition1 &&
+ condition2)
System.out.println("OK");
}
}
@@ -194,7 +199,12 @@ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
"""
class A {
void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
- if (b1 && b2 && b3 && b4 && b5 && b6) {
+ if (b1 &&
+ b2 &&
+ b3 &&
+ b4 &&
+ b5 &&
+ b6) {
System.out.println("OK");
}
}
@@ -410,7 +420,8 @@ void a(boolean condition1, boolean condition2) {
// Comment -1
/* Comment 0 */ // Comment 1
// Comment 2
- if (condition1 && condition2) /* Comment 3 */ { // Comment 4
+ if (condition1 &&
+ condition2) /* Comment 3 */ { // Comment 4
System.out.println("OK");
}
}
@@ -439,7 +450,43 @@ void a(boolean condition1, boolean condition2, boolean condition3) {
"""
class A {
void a(boolean condition1, boolean condition2, boolean condition3) {
- if (condition1 && (condition2 || condition3)) {
+ if (condition1 &&
+ (condition2 || condition3)) {
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void combineLogicalAndConditions() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
+ if (b1 && b2) {
+ if (b3 &&
+ b4) {
+ if (b5 && b6) {
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
+ if (b1 && b2 &&
+ b3 &&
+ b4 &&
+ b5 && b6) {
System.out.println("OK");
}
}
From f5d67aff2f48b378a95848bc8fa50e844ae29bd3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Sat, 27 Sep 2025 20:55:50 +0200
Subject: [PATCH 07/19] Handle comments associated with inner conditional
---
.../CombineMergeableIfStatements.java | 103 ++++++++++--
.../CombineMergeableIfStatementsTest.java | 149 +++++++++++++++++-
2 files changed, 230 insertions(+), 22 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 3f33389ee..64a69a5f7 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -21,10 +21,12 @@
import org.openrewrite.Recipe;
import org.openrewrite.Tree;
import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.style.IntelliJ;
import org.openrewrite.java.style.TabsAndIndentsStyle;
+import org.openrewrite.java.tree.Comment;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaSourceFile;
@@ -34,12 +36,13 @@
import org.openrewrite.style.Style;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
+import java.util.UUID;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
-import static org.openrewrite.internal.ListUtils.concatAll;
import static org.openrewrite.java.format.ShiftFormat.indent;
public class CombineMergeableIfStatements extends Recipe {
@@ -90,18 +93,20 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
Expression outerCondition = outerIf.getIfCondition().getTree();
Expression innerCondition = innerIf.getIfCondition().getTree();
- innerIf = indent(innerIf, getCursor(), -1);
+ UUID innerIfId = Tree.randomId();
+ getCursor().getRoot().putMessage(innerIfId.toString(), innerIf.getComments());
+ UUID outerBlockId = Tree.randomId();
+ getCursor().getRoot().putMessage(outerBlockId.toString(),
+ Optional.ofNullable(outerBlock).map(J::getComments).orElse(emptyList()));
+
doAfterVisit(new MergedConditionalVisitor<>());
return JavaTemplate.apply(
- String.format("#{any()} /*%s*/&& #{any()}", CONTINUATION_KEY),
+ String.format("#{any()} /*%s,%s,%s*/&& #{any()}", CONTINUATION_KEY, innerIfId, outerBlockId),
getCursor(),
outerCondition.getCoordinates().replace(),
outerCondition,
innerCondition)
- .withThenPart(innerIf.getThenPart())
- .withComments(concatAll(
- concatAll(outerIf.getComments(), outerBlock != null ? outerBlock.getComments() : emptyList()),
- innerIf.getComments()));
+ .withThenPart(indent(innerIf.getThenPart(), getCursor(), -1));
}
}
@@ -112,6 +117,7 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
@RequiredArgsConstructor
private static class MergedConditionalVisitor extends JavaIsoVisitor
{
+
@Nullable
private TabsAndIndentsStyle tabsAndIndentsStyle;
@@ -131,10 +137,16 @@ public Space visitSpace(@Nullable Space space, Space.Location loc, P p) {
s.getComments().get(0) instanceof TextComment) {
TextComment onlyComment = (TextComment) s.getComments().get(0);
if (onlyComment.isMultiline() &&
- CONTINUATION_KEY.equals(onlyComment.getText()) &&
+ onlyComment.getText().startsWith(CONTINUATION_KEY) &&
getCursor().firstEnclosingOrThrow(J.Binary.class).getOperator() == J.Binary.Type.And) {
- getCursor().putMessageOnFirstEnclosing(J.Binary.class, CONTINUATION_KEY, true);
- s = s.withComments(emptyList());
+ final String[] arr = onlyComment.getText().split(",");
+ final String innerIfId = arr[1];
+ final String outerBlockId = arr[2];
+ List innerIfComments = Optional.ofNullable(getCursor().getRoot().>pollMessage(innerIfId)).orElse(emptyList());
+ List outerBlockComments = Optional.ofNullable(getCursor().getRoot().>pollMessage(outerBlockId)).orElse(emptyList());
+
+ getCursor().putMessageOnFirstEnclosing(J.Binary.class, CONTINUATION_KEY, innerIfComments);
+ s = s.withComments(outerBlockComments);
}
}
@@ -145,16 +157,77 @@ public Space visitSpace(@Nullable Space space, Space.Location loc, P p) {
public J.Binary visitBinary(J.Binary binary, P p) {
J.Binary b = super.visitBinary(binary, p);
- if (Boolean.TRUE.equals(getCursor().getMessage(CONTINUATION_KEY))) {
- J.If outerIf = getCursor().firstEnclosingOrThrow(J.If.class);
- final String outerIfIndent = outerIf.getPrefix().getIndent();
- b = b.withRight(b.getRight().withPrefix(
- Space.format("\n" + continuationIndent(requireNonNull(tabsAndIndentsStyle), outerIfIndent))));
+ List comments = getCursor().pollMessage(CONTINUATION_KEY);
+ if (comments != null) {
+ final String outerIfIndent = getCursor().firstEnclosingOrThrow(J.If.class).getPrefix().getIndent();
+ final String continuationIndent = continuationIndent(requireNonNull(tabsAndIndentsStyle), outerIfIndent);
+
+ if (comments.isEmpty()) {
+ b = b.withRight(b.getRight()
+ .withPrefix(Space.format("\n" + continuationIndent)));
+ } else {
+ b = b.withRight(b.getRight()
+ .withComments(ListUtils.map(comments, c -> replaceIndent(c, continuationIndent))));
+ }
}
return b;
}
+ private Comment replaceIndent(Comment comment, String newIndent) {
+ Comment c = comment.withSuffix(replaceLastLineWithIndent(comment.getSuffix(), newIndent));
+ if (c.isMultiline() && c instanceof TextComment) {
+ TextComment tc = (TextComment) c;
+ c = tc.withText(replaceTextIndent(tc.getText(), newIndent));
+ }
+ return c;
+ }
+
+ private String replaceTextIndent(final String text, final String newIndent) {
+ final StringBuilder sb = new StringBuilder();
+ boolean found = false;
+ for (final char ch : text.toCharArray()) {
+ if (ch == ' ' || ch == '\t') {
+ if (!found) {
+ sb.append(ch);
+ }
+ } else if (ch == '\r' || ch == '\n') {
+ sb.append(ch);
+ found = true;
+ } else {
+ if (found) {
+ sb.append(newIndent);
+ if (ch == '*') {
+ sb.append(' ');
+ }
+ }
+ sb.append(ch);
+ found = false;
+ }
+ }
+ if (found) {
+ sb.append(newIndent);
+ sb.append(' ');
+ }
+ return sb.toString();
+ }
+
+ private String replaceLastLineWithIndent(String whitespace, String indent) {
+ int idx = whitespace.length() - 1;
+ while (idx >= 0) {
+ char c = whitespace.charAt(idx);
+ if (c == '\r' || c == '\n') {
+ break;
+ }
+ idx--;
+ }
+ if (idx >= 0) {
+ return whitespace.substring(0, idx + 1) + indent;
+ } else {
+ return whitespace;
+ }
+ }
+
private String continuationIndent(TabsAndIndentsStyle tabsAndIndents, String currentIndent) {
char c;
int len;
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
index 6ece54a1c..f18b3c760 100644
--- a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -214,6 +214,132 @@ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
);
}
+ @Test
+ void combineSeveralNestedIfsWithLineComments() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
+ // Comment 1.0
+ if (b1) { // Comment 1
+ if (b2) { // Comment 2
+ // Comment 3.0
+ if (b3) { // Comment 3
+ // Comment 4.0
+ if (b4) { // Comment 4
+ // Comment 5.0
+ if (b5) { // Comment 5
+ // Comment 6.0
+ // Comment 6.1
+ // Comment 6.2
+ if (b6) { // Comment 6
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
+ // Comment 1.0
+ if (b1 && // Comment 1
+ b2 && // Comment 2
+ // Comment 3.0
+ b3 && // Comment 3
+ // Comment 4.0
+ b4 && // Comment 4
+ // Comment 5.0
+ b5 && // Comment 5
+ // Comment 6.0
+ // Comment 6.1
+ // Comment 6.2
+ b6) { // Comment 6
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void combineSeveralNestedIfsWithMultilineComments() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
+ /* Comment 1.0 */
+ if (b1) { /* Comment 1 */
+ if (b2) { /* Comment 2 */
+ /* Comment 3.0 */
+ if (b3) { /* Comment 3 */
+ /* Comment 4.0 */
+ if (b4) { /*
+ * Comment 4
+ */
+ /*
+ * Comment 5.0
+ Comment 5.1
+ */
+ if (b5) { /* Comment 5 */
+ /** Comment 6.0 */
+ /**
+ * Comment 6.1
+ Comment 6.2
+ */
+ if (b6) { /* Comment 6 */
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
+ /* Comment 1.0 */
+ if (b1 && /* Comment 1 */
+ b2 && /* Comment 2 */
+ /* Comment 3.0 */
+ b3 && /* Comment 3 */
+ /* Comment 4.0 */
+ b4 && /*
+ * Comment 4
+ */
+ /*
+ * Comment 5.0
+ Comment 5.1
+ */
+ b5 && /* Comment 5 */
+ /** Comment 6.0 */
+ /**
+ * Comment 6.1
+ Comment 6.2
+ */
+ b6) { /* Comment 6 */
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
@Test
void noSimplificationWhenOuterIfHasElsePart() {
rewriteRun(
@@ -404,9 +530,14 @@ void combineMergeableIfStatementsWithComments() {
"""
class A {
void a(boolean condition1, boolean condition2) {
- // Comment -1
- if (condition1) /* Comment 0 */ { // Comment 1
- // Comment 2
+ // Comment 1.0
+ if (condition1) /* Comment 1.1 */
+ /* Comment 1.2 */ // Comment 1.3
+ /* Comment 1.4 */ { // Comment 2.0
+ // Comment 2.1
+ /*
+ * Comment 2.2
+ */ // Comment 2.3
if (condition2) /* Comment 3 */ { // Comment 4
System.out.println("OK");
}
@@ -417,10 +548,14 @@ void a(boolean condition1, boolean condition2) {
"""
class A {
void a(boolean condition1, boolean condition2) {
- // Comment -1
- /* Comment 0 */ // Comment 1
- // Comment 2
- if (condition1 &&
+ // Comment 1.0
+ if (condition1 /* Comment 1.1 */
+ /* Comment 1.2 */ // Comment 1.3
+ /* Comment 1.4 */ && // Comment 2.0
+ // Comment 2.1
+ /*
+ * Comment 2.2
+ */ // Comment 2.3
condition2) /* Comment 3 */ { // Comment 4
System.out.println("OK");
}
From 48b17e92cafb8cf5cbdbd6a86b77f5dcbc39ee3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Wed, 15 Oct 2025 21:09:20 +0200
Subject: [PATCH 08/19] Update
src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
.../staticanalysis/CombineMergeableIfStatements.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 64a69a5f7..872801dfe 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -223,8 +223,7 @@ private String replaceLastLineWithIndent(String whitespace, String indent) {
}
if (idx >= 0) {
return whitespace.substring(0, idx + 1) + indent;
- } else {
- return whitespace;
+ return whitespace;
}
}
From cba1bca57de954d2120cca0eeacc3d37845a9c0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Wed, 15 Oct 2025 22:14:45 +0200
Subject: [PATCH 09/19] Fix misplaced return in previous suggestion
---
.../staticanalysis/CombineMergeableIfStatements.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 872801dfe..3bc654484 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -223,8 +223,8 @@ private String replaceLastLineWithIndent(String whitespace, String indent) {
}
if (idx >= 0) {
return whitespace.substring(0, idx + 1) + indent;
- return whitespace;
}
+ return whitespace;
}
private String continuationIndent(TabsAndIndentsStyle tabsAndIndents, String currentIndent) {
From 4cac248024aab5b6980fd5e72a529852025053d7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Thu, 29 Jan 2026 17:42:28 +0100
Subject: [PATCH 10/19] Update
src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
.../openrewrite/staticanalysis/CombineMergeableIfStatements.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 3bc654484..2433897af 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -15,6 +15,7 @@
*/
package org.openrewrite.staticanalysis;
+import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
From 998d891cb63b6b064c4eafb03fa3bc77a0d2ffaa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Thu, 29 Jan 2026 17:42:39 +0100
Subject: [PATCH 11/19] Update
src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
---
.../CombineMergeableIfStatements.java | 20 ++++++-------------
1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 2433897af..6c979edf8 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -50,20 +50,12 @@ public class CombineMergeableIfStatements extends Recipe {
private static final String CONTINUATION_KEY = "continuationAfterLogicalAnd";
- @Override
- public String getDisplayName() {
- // language=markdown
- return "Mergeable `if` statements should be combined";
- }
-
- @Override
- public String getDescription() {
- // language=markdown
- return "Mergeable `if` statements should be combined.";
- }
-
- @Override
- public Set getTags() {
+ @Getter
+ final String displayName = "Mergeable `if` statements should be combined";
+ @Getter
+ final String description = "Mergeable `if` statements should be combined.";
+ @Getter
+ final Set tags = singleton("RSPEC-S1066");
return singleton("RSPEC-S1066");
}
From b82b1abb024103fd179f69cae445310f270a9ee6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Thu, 29 Jan 2026 18:01:45 +0100
Subject: [PATCH 12/19] Update CombineMergeableIfStatements.java
---
.../staticanalysis/CombineMergeableIfStatements.java | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 6c979edf8..e71e23484 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -56,8 +56,6 @@ public class CombineMergeableIfStatements extends Recipe {
final String description = "Mergeable `if` statements should be combined.";
@Getter
final Set tags = singleton("RSPEC-S1066");
- return singleton("RSPEC-S1066");
- }
@Override
public TreeVisitor, ExecutionContext> getVisitor() {
From f0c659ef9ba5f3aab6d22ee1a319af4841448433 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9=20Kaplan?=
<228053663+olwispe@users.noreply.github.com>
Date: Thu, 29 Jan 2026 19:39:10 +0100
Subject: [PATCH 13/19] Updated recipes.csv as suggested
---
src/main/resources/META-INF/rewrite/recipes.csv | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/main/resources/META-INF/rewrite/recipes.csv b/src/main/resources/META-INF/rewrite/recipes.csv
index 01f9f3cb9..8b3d86e0a 100644
--- a/src/main/resources/META-INF/rewrite/recipes.csv
+++ b/src/main/resources/META-INF/rewrite/recipes.csv
@@ -20,6 +20,7 @@ maven,org.openrewrite.recipe:rewrite-static-analysis,org.openrewrite.staticanaly
maven,org.openrewrite.recipe:rewrite-static-analysis,org.openrewrite.staticanalysis.CatchClauseOnlyRethrows,Catch clause should do more than just rethrow,A `catch` clause that only rethrows the caught exception is unnecessary. Letting the exception bubble up as normal achieves the same result with less code.,1,,Static analysis and remediation,,Remediations for issues identified by SAST tools.,
maven,org.openrewrite.recipe:rewrite-static-analysis,org.openrewrite.staticanalysis.ChainStringBuilderAppendCalls,Chain `StringBuilder.append()` calls,"String concatenation within calls to `StringBuilder.append()` causes unnecessary memory allocation. Except for concatenations of String literals, which are joined together at compile time. Replaces inefficient concatenations with chained calls to `StringBuilder.append()`.",1,,Static analysis and remediation,,Remediations for issues identified by SAST tools.,
maven,org.openrewrite.recipe:rewrite-static-analysis,org.openrewrite.staticanalysis.CollectionToArrayShouldHaveProperType,'Collection.toArray()' should be passed an array of the proper type,"Using `Collection.toArray()` without parameters returns an `Object[]`, which requires casting. It is more efficient and clearer to use `Collection.toArray(new T[0])` instead.",1,,Static analysis and remediation,,Remediations for issues identified by SAST tools.,
+maven,org.openrewrite.recipe:rewrite-static-analysis,org.openrewrite.staticanalysis.CombineMergeableIfStatements,Mergeable `if` statements should be combined,Mergeable `if` statements should be combined.,1,,Static analysis and remediation,,Remediations for issues identified by SAST tools.,
maven,org.openrewrite.recipe:rewrite-static-analysis,org.openrewrite.staticanalysis.CombineSemanticallyEqualCatchBlocks,Combine semantically equal catch blocks,Combine catches in a try that contain semantically equivalent blocks. No change will be made when a caught exception exists if combining catches may change application behavior or type attribution is missing.,1,,Static analysis and remediation,,Remediations for issues identified by SAST tools.,
maven,org.openrewrite.recipe:rewrite-static-analysis,org.openrewrite.staticanalysis.CompareEnumsWithEqualityOperator,Enum values should be compared with "==",Replaces `Enum equals(java.lang.Object)` with `Enum == java.lang.Object`. An `!Enum equals(java.lang.Object)` will change to `!=`.,1,,Static analysis and remediation,,Remediations for issues identified by SAST tools.,
maven,org.openrewrite.recipe:rewrite-static-analysis,org.openrewrite.staticanalysis.ControlFlowIndentation,Control flow statement indentation,"Program flow control statements like `if`, `while`, and `for` can omit curly braces when they apply to only a single statement. This recipe ensures that any statements which follow that statement are correctly indented to show they are not part of the flow control statement.",1,,Static analysis and remediation,,Remediations for issues identified by SAST tools.,
From 8e0cbdbf33199fc7e1275c87a110689f2a2c2247 Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Tue, 24 Mar 2026 15:34:11 +0100
Subject: [PATCH 14/19] Polish
---
.../CombineMergeableIfStatements.java | 13 ++++++++++---
.../CombineMergeableIfStatementsTest.java | 18 +++++++++---------
2 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index e71e23484..da96f62e8 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -15,8 +15,10 @@
*/
package org.openrewrite.staticanalysis;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
+import lombok.Value;
import org.jspecify.annotations.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
@@ -36,6 +38,7 @@
import org.openrewrite.java.tree.TextComment;
import org.openrewrite.style.Style;
+import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -46,16 +49,20 @@
import static java.util.Objects.requireNonNull;
import static org.openrewrite.java.format.ShiftFormat.indent;
+@EqualsAndHashCode(callSuper = false)
+@Value
public class CombineMergeableIfStatements extends Recipe {
private static final String CONTINUATION_KEY = "continuationAfterLogicalAnd";
@Getter
- final String displayName = "Mergeable `if` statements should be combined";
+ String displayName = "Mergeable `if` statements should be combined";
@Getter
- final String description = "Mergeable `if` statements should be combined.";
+ String description = "Mergeable `if` statements should be combined.";
@Getter
- final Set tags = singleton("RSPEC-S1066");
+ Set tags = singleton("RSPEC-S1066");
+ @Getter
+ Duration estimatedEffortPerOccurrence = Duration.ofMinutes(2);
@Override
public TreeVisitor, ExecutionContext> getVisitor() {
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
index f18b3c760..c599aad9b 100644
--- a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -341,7 +341,7 @@ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
}
@Test
- void noSimplificationWhenOuterIfHasElsePart() {
+ void doNotChangeWhenOuterIfHasElsePart() {
rewriteRun(
// language=java
java(
@@ -363,7 +363,7 @@ void a(boolean condition1, boolean condition2) {
}
@Test
- void noSimplificationWhenOuterIfHasEmptyBlockAsElsePart() {
+ void doNotChangeWhenOuterIfHasEmptyBlockAsElsePart() {
rewriteRun(
// language=java
java(
@@ -384,7 +384,7 @@ void a(boolean condition1, boolean condition2) {
}
@Test
- void noSimplificationWhenOuterIfHasEmptyStatementAsElsePart() {
+ void doNotChangeWhenOuterIfHasEmptyStatementAsElsePart() {
rewriteRun(
// language=java
java(
@@ -404,7 +404,7 @@ void a(boolean condition1, boolean condition2) {
}
@Test
- void noSimplificationWhenOuterIfHasOneStatementInThenPartButIsNotIf() {
+ void doNotChangeWhenOuterIfHasOneStatementInThenPartButIsNotIf() {
rewriteRun(
// language=java
java(
@@ -422,7 +422,7 @@ void a(boolean condition1, boolean condition2) {
}
@Test
- void noSimplificationWhenOuterIfHasOneStatementWithoutBlockInThenPartButIsNotIf() {
+ void doNotChangeWhenOuterIfHasOneStatementWithoutBlockInThenPartButIsNotIf() {
rewriteRun(
// language=java
java(
@@ -439,7 +439,7 @@ void a(boolean condition1, boolean condition2) {
}
@Test
- void noSimplificationWhenOuterIfHasTwoStatementsInThenPart() {
+ void doNotChangeWhenOuterIfHasTwoStatementsInThenPart() {
rewriteRun(
// language=java
java(
@@ -460,7 +460,7 @@ void a(boolean condition1, boolean condition2) {
}
@Test
- void noSimplificationWhenInnerIfHasElsePart() {
+ void doNotChangeWhenInnerIfHasElsePart() {
rewriteRun(
// language=java
java(
@@ -482,7 +482,7 @@ void a(boolean condition1, boolean condition2) {
}
@Test
- void noSimplificationWhenInnerIfHasEmptyBlockAsElsePart() {
+ void doNotChangeWhenInnerIfHasEmptyBlockAsElsePart() {
rewriteRun(
// language=java
java(
@@ -503,7 +503,7 @@ void a(boolean condition1, boolean condition2) {
}
@Test
- void noSimplificationWhenInnerIfHasEmptyStatementAsElsePart() {
+ void doNotChangeWhenInnerIfHasEmptyStatementAsElsePart() {
rewriteRun(
// language=java
java(
From 488123b16fd9b90f0006f0e373644ab9dde30c0d Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Tue, 24 Mar 2026 21:58:15 +0100
Subject: [PATCH 15/19] Fix indentation bug with non-4-space indent styles
Replace ShiftFormat.indent(-1) with a custom shiftLeft that computes
the actual indent difference between the inner and outer if statements.
indent(-1) always used the default 4-space indent size, causing broken
indentation in repos using 2-space indent (e.g., Apache Accumulo).
Add test case for 2-space indentation.
---
.../CombineMergeableIfStatements.java | 52 ++++++++++++++++++-
.../CombineMergeableIfStatementsTest.java | 30 +++++++++++
2 files changed, 80 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index da96f62e8..4323e54f3 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -47,7 +47,6 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
-import static org.openrewrite.java.format.ShiftFormat.indent;
@EqualsAndHashCode(callSuper = false)
@Value
@@ -98,13 +97,19 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
Optional.ofNullable(outerBlock).map(J::getComments).orElse(emptyList()));
doAfterVisit(new MergedConditionalVisitor<>());
+
+ // Compute actual indent difference between inner and outer if
+ String outerIndent = outerIf.getPrefix().getIndent();
+ String innerIndent = innerIf.getPrefix().getIndent();
+ int indentSize = innerIndent.length() - outerIndent.length();
+
return JavaTemplate.apply(
String.format("#{any()} /*%s,%s,%s*/&& #{any()}", CONTINUATION_KEY, innerIfId, outerBlockId),
getCursor(),
outerCondition.getCoordinates().replace(),
outerCondition,
innerCondition)
- .withThenPart(indent(innerIf.getThenPart(), getCursor(), -1));
+ .withThenPart(shiftLeft(innerIf.getThenPart(), indentSize));
}
}
@@ -113,6 +118,49 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
};
}
+ @SuppressWarnings("unchecked")
+ private static J2 shiftLeft(J j, int shift) {
+ if (shift <= 0) {
+ return (J2) j;
+ }
+ return (J2) new JavaIsoVisitor() {
+ @Override
+ public Space visitSpace(Space space, Space.Location loc, Integer p) {
+ Space s = super.visitSpace(space, loc, p);
+ String ws = s.getWhitespace();
+ if (ws.contains("\n") || ws.contains("\r")) {
+ s = s.withWhitespace(trimRight(ws, shift));
+ }
+ List comments = s.getComments();
+ if (!comments.isEmpty()) {
+ s = s.withComments(ListUtils.map(comments, c -> {
+ String suffix = c.getSuffix();
+ if (suffix.contains("\n") || suffix.contains("\r")) {
+ return c.withSuffix(trimRight(suffix, shift));
+ }
+ return c;
+ }));
+ }
+ return s;
+ }
+
+ private String trimRight(String whitespace, int amount) {
+ int lastNewline = Math.max(whitespace.lastIndexOf('\n'), whitespace.lastIndexOf('\r'));
+ if (lastNewline < 0) {
+ return whitespace;
+ }
+ // Handle \r\n
+ int lineStart = lastNewline + 1;
+ if (lastNewline < whitespace.length() - 1 && whitespace.charAt(lastNewline) == '\r' && whitespace.charAt(lastNewline + 1) == '\n') {
+ lineStart = lastNewline + 2;
+ }
+ String indent = whitespace.substring(lineStart);
+ int newLen = Math.max(0, indent.length() - amount);
+ return whitespace.substring(0, lineStart) + indent.substring(0, newLen);
+ }
+ }.visitNonNull(j, 0);
+ }
+
@RequiredArgsConstructor
private static class MergedConditionalVisitor extends JavaIsoVisitor
{
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
index c599aad9b..558167103 100644
--- a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -630,4 +630,34 @@ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
)
);
}
+
+ @Test
+ void combineMergeableIfStatementsWithTwoSpaceIndent() {
+ rewriteRun(
+ // language=java
+ java(
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1) {
+ if (condition2) {
+ System.out.println("OK");
+ }
+ }
+ }
+ }
+ """,
+ """
+ class A {
+ void a(boolean condition1, boolean condition2) {
+ if (condition1 &&
+ condition2) {
+ System.out.println("OK");
+ }
+ }
+ }
+ """
+ )
+ );
+ }
}
From b0dc48ac99091f185b1c6171877fe1622570e7eb Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Tue, 24 Mar 2026 22:20:02 +0100
Subject: [PATCH 16/19] Add working-set to .gitignore for Moderne CLI
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 892fee6d3..8bc70e164 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,3 +13,4 @@ bin/
.gitmodules
docs
Sonar.MD
+working-set*/
From 4a8f4db5957303f44d02daa4b4e8202adb73236a Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Mon, 30 Mar 2026 14:08:24 +0200
Subject: [PATCH 17/19] Apply suggestions from code review
Co-authored-by: Tim te Beek
---
.../staticanalysis/CombineMergeableIfStatements.java | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 4323e54f3..3d98da5ae 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -54,13 +54,9 @@ public class CombineMergeableIfStatements extends Recipe {
private static final String CONTINUATION_KEY = "continuationAfterLogicalAnd";
- @Getter
String displayName = "Mergeable `if` statements should be combined";
- @Getter
String description = "Mergeable `if` statements should be combined.";
- @Getter
Set tags = singleton("RSPEC-S1066");
- @Getter
Duration estimatedEffortPerOccurrence = Duration.ofMinutes(2);
@Override
From 9be76582b2b606f5bfc43d6996b263a403e25197 Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Mon, 30 Mar 2026 14:23:41 +0200
Subject: [PATCH 18/19] Use ShiftFormat.indent() instead of custom shiftLeft
method
Replace hand-rolled indentation shifting with the existing
ShiftFormat.indent() utility from rewrite-java, which properly
handles tabs vs spaces based on TabsAndIndentsStyle.
---
.../CombineMergeableIfStatements.java | 52 ++-----------------
.../CombineMergeableIfStatementsTest.java | 11 +++-
2 files changed, 13 insertions(+), 50 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 3d98da5ae..8781551d2 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -38,6 +38,8 @@
import org.openrewrite.java.tree.TextComment;
import org.openrewrite.style.Style;
+import static org.openrewrite.java.format.ShiftFormat.indent;
+
import java.time.Duration;
import java.util.List;
import java.util.Optional;
@@ -94,18 +96,13 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
doAfterVisit(new MergedConditionalVisitor<>());
- // Compute actual indent difference between inner and outer if
- String outerIndent = outerIf.getPrefix().getIndent();
- String innerIndent = innerIf.getPrefix().getIndent();
- int indentSize = innerIndent.length() - outerIndent.length();
-
return JavaTemplate.apply(
String.format("#{any()} /*%s,%s,%s*/&& #{any()}", CONTINUATION_KEY, innerIfId, outerBlockId),
getCursor(),
outerCondition.getCoordinates().replace(),
outerCondition,
innerCondition)
- .withThenPart(shiftLeft(innerIf.getThenPart(), indentSize));
+ .withThenPart(indent(innerIf.getThenPart(), getCursor(), -1));
}
}
@@ -114,49 +111,6 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
};
}
- @SuppressWarnings("unchecked")
- private static J2 shiftLeft(J j, int shift) {
- if (shift <= 0) {
- return (J2) j;
- }
- return (J2) new JavaIsoVisitor() {
- @Override
- public Space visitSpace(Space space, Space.Location loc, Integer p) {
- Space s = super.visitSpace(space, loc, p);
- String ws = s.getWhitespace();
- if (ws.contains("\n") || ws.contains("\r")) {
- s = s.withWhitespace(trimRight(ws, shift));
- }
- List comments = s.getComments();
- if (!comments.isEmpty()) {
- s = s.withComments(ListUtils.map(comments, c -> {
- String suffix = c.getSuffix();
- if (suffix.contains("\n") || suffix.contains("\r")) {
- return c.withSuffix(trimRight(suffix, shift));
- }
- return c;
- }));
- }
- return s;
- }
-
- private String trimRight(String whitespace, int amount) {
- int lastNewline = Math.max(whitespace.lastIndexOf('\n'), whitespace.lastIndexOf('\r'));
- if (lastNewline < 0) {
- return whitespace;
- }
- // Handle \r\n
- int lineStart = lastNewline + 1;
- if (lastNewline < whitespace.length() - 1 && whitespace.charAt(lastNewline) == '\r' && whitespace.charAt(lastNewline + 1) == '\n') {
- lineStart = lastNewline + 2;
- }
- String indent = whitespace.substring(lineStart);
- int newLen = Math.max(0, indent.length() - amount);
- return whitespace.substring(0, lineStart) + indent.substring(0, newLen);
- }
- }.visitNonNull(j, 0);
- }
-
@RequiredArgsConstructor
private static class MergedConditionalVisitor extends JavaIsoVisitor
{
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
index 558167103..ba687e507 100644
--- a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -17,9 +17,15 @@
import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
+import org.openrewrite.Tree;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.java.style.TabsAndIndentsStyle;
+import org.openrewrite.style.NamedStyles;
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;
+import static java.util.Collections.emptySet;
+import static java.util.Collections.singletonList;
import static org.openrewrite.java.Assertions.java;
import static org.openrewrite.java.Assertions.version;
@@ -634,6 +640,9 @@ void a(boolean b1, boolean b2, boolean b3, boolean b4, boolean b5, boolean b6) {
@Test
void combineMergeableIfStatementsWithTwoSpaceIndent() {
rewriteRun(
+ spec -> spec.parser(JavaParser.fromJavaVersion().styles(singletonList(
+ new NamedStyles(Tree.randomId(), "test", "test", "test", emptySet(),
+ singletonList(new TabsAndIndentsStyle(false, 2, 2, 4, false)))))),
// language=java
java(
"""
@@ -651,7 +660,7 @@ void a(boolean condition1, boolean condition2) {
class A {
void a(boolean condition1, boolean condition2) {
if (condition1 &&
- condition2) {
+ condition2) {
System.out.println("OK");
}
}
From 5c530f34bc10b618b28be6653e42103f18f78d26 Mon Sep 17 00:00:00 2001
From: Tim te Beek
Date: Mon, 30 Mar 2026 14:42:42 +0200
Subject: [PATCH 19/19] Use autoFormat instead of ShiftFormat for thenPart
indentation
Replace ShiftFormat.indent() with autoFormat(merged, ctx) which
delegates indentation correction to the standard formatting pipeline.
---
.../staticanalysis/CombineMergeableIfStatements.java | 8 +++-----
.../staticanalysis/CombineMergeableIfStatementsTest.java | 4 ++--
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
index 8781551d2..ce450c931 100644
--- a/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
+++ b/src/main/java/org/openrewrite/staticanalysis/CombineMergeableIfStatements.java
@@ -16,7 +16,6 @@
package org.openrewrite.staticanalysis;
import lombok.EqualsAndHashCode;
-import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import org.jspecify.annotations.Nullable;
@@ -38,8 +37,6 @@
import org.openrewrite.java.tree.TextComment;
import org.openrewrite.style.Style;
-import static org.openrewrite.java.format.ShiftFormat.indent;
-
import java.time.Duration;
import java.util.List;
import java.util.Optional;
@@ -96,13 +93,14 @@ public J.If visitIf(J.If iff, ExecutionContext ctx) {
doAfterVisit(new MergedConditionalVisitor<>());
- return JavaTemplate.apply(
+ J.If merged = JavaTemplate.apply(
String.format("#{any()} /*%s,%s,%s*/&& #{any()}", CONTINUATION_KEY, innerIfId, outerBlockId),
getCursor(),
outerCondition.getCoordinates().replace(),
outerCondition,
innerCondition)
- .withThenPart(indent(innerIf.getThenPart(), getCursor(), -1));
+ .withThenPart(innerIf.getThenPart());
+ return autoFormat(merged, ctx);
}
}
diff --git a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
index ba687e507..11245d624 100644
--- a/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
+++ b/src/test/java/org/openrewrite/staticanalysis/CombineMergeableIfStatementsTest.java
@@ -563,8 +563,8 @@ void a(boolean condition1, boolean condition2) {
* Comment 2.2
*/ // Comment 2.3
condition2) /* Comment 3 */ { // Comment 4
- System.out.println("OK");
- }
+ System.out.println("OK");
+ }
}
}
"""