Bug 572790 - [AutoRefactor #74/153] 1 if rather than duplicate

Merge consecutive if statements with same code block that end with a
jump statement:

Given:
        if (i1 == 0) {
            System.out.println("The same code");
            return;
        }
        if (i1 == 1) {
            System.out.println("The same code");
            return;
        }
        System.out.println("Next code");

When:
Applying "One if rather than duplicate blocks that fall through" clean
up...

Then:
        if ((i1 == 0) || (i1 == 1)) {
            System.out.println("The same code");
            return;
        }
        System.out.println("Next code");

Change-Id: I94d94c3f1bb101f74a10d320baff0ae3a938a4d6
Signed-off-by: Fabrice Tiercelin <fabrice.tiercelin@yahoo.fr>
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java
index 2461d05..02d573d 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.java
@@ -186,6 +186,7 @@
 	public static String ObjectsEqualsCleanup_description;
 
 	public static String OperandFactorizationCleanUp_description;
+	public static String OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp_description;
 
 	public static String InvertEqualsCleanUp_description;
 	public static String CheckSignOfBitwiseOperation_description;
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties
index f6846ae..6090e9e 100644
--- a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/MultiFixMessages.properties
@@ -168,6 +168,7 @@
 ObjectsEqualsCleanup_description=Use Objects.equals() in the equals method implementation
 
 OperandFactorizationCleanUp_description=Replace (X && Y) || (X && Z) by (X && (Y || Z))
+OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp_description=Single 'if' statement rather than duplicate blocks that fall through
 
 InvertEqualsCleanUp_description=Avoid Object.equals() or String.equalsIgnoreCase() on null objects
 CheckSignOfBitwiseOperation_description=Use != 0 instead of > 0 when comparing the result of a bitwise expression
diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/OneIfRatherThanDuplicateBlocksThatFallThroughCleanUpCore.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/OneIfRatherThanDuplicateBlocksThatFallThroughCleanUpCore.java
new file mode 100644
index 0000000..7008603
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/OneIfRatherThanDuplicateBlocksThatFallThroughCleanUpCore.java
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.manipulation.CleanUpContextCore;
+import org.eclipse.jdt.core.manipulation.CleanUpRequirementsCore;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.fix.CleanUpConstants;
+import org.eclipse.jdt.internal.corext.fix.OneIfRatherThanDuplicateBlocksThatFallThroughFixCore;
+
+public class OneIfRatherThanDuplicateBlocksThatFallThroughCleanUpCore extends AbstractCleanUpCore {
+	public OneIfRatherThanDuplicateBlocksThatFallThroughCleanUpCore(final Map<String, String> options) {
+		super(options);
+	}
+
+	public OneIfRatherThanDuplicateBlocksThatFallThroughCleanUpCore() {
+	}
+
+	@Override
+	public CleanUpRequirementsCore getRequirementsCore() {
+		return new CleanUpRequirementsCore(requireAST(), false, false, null);
+	}
+
+	public boolean requireAST() {
+		return isEnabled(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH);
+	}
+
+	@Override
+	public ICleanUpFixCore createFixCore(final CleanUpContextCore context) throws CoreException {
+		CompilationUnit compilationUnit= context.getAST();
+
+		if (compilationUnit == null || !isEnabled(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH)) {
+			return null;
+		}
+
+		return OneIfRatherThanDuplicateBlocksThatFallThroughFixCore.createCleanUp(compilationUnit);
+	}
+
+	@Override
+	public String[] getStepDescriptions() {
+		if (isEnabled(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH)) {
+			return new String[] {MultiFixMessages.OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp_description};
+		}
+
+		return new String[0];
+	}
+
+	@Override
+	public String getPreview() {
+		StringBuilder bld= new StringBuilder();
+
+		if (isEnabled(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH)) {
+			bld.append("if (isActive || isValid) {\n"); //$NON-NLS-1$
+		} else {
+			bld.append("if (isActive) {\n"); //$NON-NLS-1$
+		}
+
+		bld.append("    System.out.println(\"The same code\");\n"); //$NON-NLS-1$
+		bld.append("    throw new NullPointerException();\n"); //$NON-NLS-1$
+		bld.append("}\n"); //$NON-NLS-1$
+
+		if (!isEnabled(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH)) {
+			bld.append("if (isValid) {\n"); //$NON-NLS-1$
+			bld.append("    System.out.println(\"The same code\");\n"); //$NON-NLS-1$
+			bld.append("    throw new NullPointerException();\n"); //$NON-NLS-1$
+			bld.append("}\n"); //$NON-NLS-1$
+		}
+
+		bld.append("System.out.println(\"Next code\");\n"); //$NON-NLS-1$
+
+		if (isEnabled(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH)) {
+			bld.append("\n\n\n\n"); //$NON-NLS-1$
+		}
+
+		return bld.toString();
+	}
+}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java
index 1f02713..652118c 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java
@@ -1596,6 +1596,18 @@
 	public static final String CONTROLFLOW_MERGE= "cleanup.controlflow_merge"; //$NON-NLS-1$
 
 	/**
+	 * Merge consecutive <code>if</code> statements with same code block that end with a jump statement.
+	 * <p>
+	 * Possible values: {TRUE, FALSE}
+	 * <p>
+	 *
+	 * @see CleanUpOptionsCore#TRUE
+	 * @see CleanUpOptionsCore#FALSE
+	 * @since 4.20
+	 */
+	public static final String ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH= "cleanup.one_if_rather_than_duplicate_blocks_that_fall_through"; //$NON-NLS-1$
+
+	/**
 	 * Merges blocks that end with a jump statement into the following same code.
 	 * <p>
 	 * Possible values: {TRUE, FALSE}
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
index f9943e6..edbc35f 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.java
@@ -170,6 +170,8 @@
 	public static String ArrayWithCurlyFix_description;
 	public static String ReturnExpressionFix_description;
 
+	public static String OneIfRatherThanDuplicateBlocksThatFallThroughFix_description;
+
 	public static String TypeAnnotationFix_move;
 	public static String TypeAnnotationFix_remove;
 	public static String ConstantsCleanUpFix_refactor;
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
index d3ccfd0..7f88ec9 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/FixMessages.properties
@@ -157,6 +157,8 @@
 ArrayWithCurlyFix_description=Create array with curly
 ReturnExpressionFix_description=Remove variable assignment before return
 
+OneIfRatherThanDuplicateBlocksThatFallThroughFix_description=Single 'if' statement rather than duplicate blocks that fall through
+
 TypeAnnotationFix_move=Move type annotation
 TypeAnnotationFix_remove=Remove type annotation
 ConstantsCleanUpFix_refactor=Replace system property with Java method
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/OneIfRatherThanDuplicateBlocksThatFallThroughFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/OneIfRatherThanDuplicateBlocksThatFallThroughFixCore.java
new file mode 100644
index 0000000..86013cb
--- /dev/null
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/OneIfRatherThanDuplicateBlocksThatFallThroughFixCore.java
@@ -0,0 +1,177 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.corext.fix;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.Expression;
+import org.eclipse.jdt.core.dom.IfStatement;
+import org.eclipse.jdt.core.dom.InfixExpression;
+import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
+import org.eclipse.jdt.core.dom.rewrite.TargetSourceRangeComputer;
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+
+import org.eclipse.jdt.internal.ui.fix.MultiFixMessages;
+
+public class OneIfRatherThanDuplicateBlocksThatFallThroughFixCore extends CompilationUnitRewriteOperationsFixCore {
+	public static final class OneIfRatherThanDuplicateBlocksThatFallThroughFinder extends ASTVisitor {
+		private List<CompilationUnitRewriteOperation> fResult;
+
+		public OneIfRatherThanDuplicateBlocksThatFallThroughFinder(List<CompilationUnitRewriteOperation> ops) {
+			fResult= ops;
+		}
+
+		@Override
+		public boolean visit(final Block visited) {
+			SuccessiveIfVisitor successiveIfVisitor= new SuccessiveIfVisitor(visited);
+			visited.accept(successiveIfVisitor);
+			return successiveIfVisitor.result;
+		}
+
+		private final class SuccessiveIfVisitor extends ASTVisitor {
+			private final Block startNode;
+			private boolean result= true;
+
+			public SuccessiveIfVisitor(final Block startNode) {
+				this.startNode= startNode;
+			}
+
+			@Override
+			public boolean visit(final Block node) {
+				return startNode == node;
+			}
+
+			@Override
+			public boolean visit(final IfStatement visited) {
+				if (result && ASTNodes.fallsThrough(visited.getThenStatement())) {
+					List<IfStatement> duplicateIfBlocks= new ArrayList<>(ASTNodes.EXCESSIVE_OPERAND_NUMBER - 1);
+					AtomicInteger operandCount= new AtomicInteger(ASTNodes.getNbOperands(visited.getExpression()));
+					duplicateIfBlocks.add(visited);
+
+					while (addOneMoreIf(duplicateIfBlocks, operandCount)) {
+						// OK continue
+					}
+
+					if (duplicateIfBlocks.size() > 1) {
+						fResult.add(new OneIfRatherThanDuplicateBlocksThatFallThroughOperation(duplicateIfBlocks));
+						result= false;
+						return false;
+					}
+				}
+
+				return true;
+			}
+
+			private boolean addOneMoreIf(final List<IfStatement> duplicateIfBlocks, final AtomicInteger operandCount) {
+				IfStatement lastBlock= duplicateIfBlocks.get(duplicateIfBlocks.size() - 1);
+
+				if (lastBlock.getElseStatement() == null) {
+					IfStatement nextSibling= ASTNodes.as(ASTNodes.getNextSibling(lastBlock), IfStatement.class);
+
+					if (nextSibling != null
+							&& nextSibling.getElseStatement() == null
+							&& operandCount.get() + ASTNodes.getNbOperands(nextSibling.getExpression()) < ASTNodes.EXCESSIVE_OPERAND_NUMBER
+							&& ASTNodes.match(lastBlock.getThenStatement(), nextSibling.getThenStatement())) {
+						operandCount.addAndGet(ASTNodes.getNbOperands(nextSibling.getExpression()));
+						duplicateIfBlocks.add(nextSibling);
+						return true;
+					}
+				}
+
+				return false;
+			}
+		}
+	}
+
+	private static class OneIfRatherThanDuplicateBlocksThatFallThroughOperation extends CompilationUnitRewriteOperation {
+		private final List<IfStatement> duplicateIfBlocks;
+
+		public OneIfRatherThanDuplicateBlocksThatFallThroughOperation(final List<IfStatement> duplicateIfBlocks) {
+			this.duplicateIfBlocks= duplicateIfBlocks;
+		}
+
+		@Override
+		public void rewriteAST(final CompilationUnitRewrite cuRewrite, final LinkedProposalModelCore linkedModel) throws CoreException {
+			ASTRewrite rewrite= cuRewrite.getASTRewrite();
+			AST ast= cuRewrite.getRoot().getAST();
+			TextEditGroup group= createTextEditGroup(MultiFixMessages.OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp_description, cuRewrite);
+			rewrite.setTargetSourceRangeComputer(new TargetSourceRangeComputer() {
+				@Override
+				public SourceRange computeSourceRange(final ASTNode nodeWithComment) {
+					if (Boolean.TRUE.equals(nodeWithComment.getProperty(ASTNodes.UNTOUCH_COMMENT))) {
+						return new SourceRange(nodeWithComment.getStartPosition(), nodeWithComment.getLength());
+					}
+
+					return super.computeSourceRange(nodeWithComment);
+				}
+			});
+
+			List<Expression> newConditions= new ArrayList<>(duplicateIfBlocks.size());
+
+			for (IfStatement ifStatement : duplicateIfBlocks) {
+				InfixExpression oneOriginalCondition= ASTNodes.as(ifStatement.getExpression(), InfixExpression.class);
+
+				if (ASTNodes.hasOperator(oneOriginalCondition, InfixExpression.Operator.CONDITIONAL_OR)) {
+					newConditions.add(ASTNodes.createMoveTarget(rewrite, ASTNodes.getUnparenthesedExpression(ifStatement.getExpression())));
+				} else {
+					newConditions.add(ASTNodeFactory.parenthesizeIfNeeded(ast, ASTNodes.createMoveTarget(rewrite, ifStatement.getExpression())));
+				}
+			}
+
+			InfixExpression newCondition= ast.newInfixExpression();
+			newCondition.setOperator(InfixExpression.Operator.CONDITIONAL_OR);
+			newCondition.setLeftOperand(newConditions.remove(0));
+			newCondition.setRightOperand(newConditions.remove(0));
+			newCondition.extendedOperands().addAll(newConditions);
+
+			for (int i= 0; i < duplicateIfBlocks.size() - 1; i++) {
+				ASTNodes.removeButKeepComment(rewrite, duplicateIfBlocks.get(i), group);
+			}
+
+			rewrite.replace(duplicateIfBlocks.get(duplicateIfBlocks.size() - 1).getExpression(), newCondition, group);
+		}
+	}
+
+	public static ICleanUpFixCore createCleanUp(final CompilationUnit compilationUnit) {
+		List<CompilationUnitRewriteOperation> operations= new ArrayList<>();
+		OneIfRatherThanDuplicateBlocksThatFallThroughFinder finder= new OneIfRatherThanDuplicateBlocksThatFallThroughFinder(operations);
+		compilationUnit.accept(finder);
+
+		if (operations.isEmpty()) {
+			return null;
+		}
+
+		CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[0]);
+		return new OneIfRatherThanDuplicateBlocksThatFallThroughFixCore(FixMessages.OneIfRatherThanDuplicateBlocksThatFallThroughFix_description, compilationUnit, ops);
+	}
+
+	protected OneIfRatherThanDuplicateBlocksThatFallThroughFixCore(final String name, final CompilationUnit compilationUnit, final CompilationUnitRewriteOperationsFixCore.CompilationUnitRewriteOperation[] fixRewriteOperations) {
+		super(name, compilationUnit, fixRewriteOperations);
+	}
+}
diff --git a/org.eclipse.jdt.ui.tests/performance/org/eclipse/jdt/ui/tests/performance/views/CleanUpPerfTest.java b/org.eclipse.jdt.ui.tests/performance/org/eclipse/jdt/ui/tests/performance/views/CleanUpPerfTest.java
index 260bf40..f707b3b 100644
--- a/org.eclipse.jdt.ui.tests/performance/org/eclipse/jdt/ui/tests/performance/views/CleanUpPerfTest.java
+++ b/org.eclipse.jdt.ui.tests/performance/org/eclipse/jdt/ui/tests/performance/views/CleanUpPerfTest.java
@@ -85,6 +85,7 @@
 import org.eclipse.jdt.internal.ui.fix.LazyLogicalCleanUp;
 import org.eclipse.jdt.internal.ui.fix.MapCloningCleanUp;
 import org.eclipse.jdt.internal.ui.fix.MergeConditionalBlocksCleanUp;
+import org.eclipse.jdt.internal.ui.fix.OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp;
 import org.eclipse.jdt.internal.ui.fix.PlainReplacementCleanUp;
 import org.eclipse.jdt.internal.ui.fix.PrimitiveComparisonCleanUp;
 import org.eclipse.jdt.internal.ui.fix.PrimitiveIntRatherThanWrapperCleanUp;
@@ -754,6 +755,22 @@
 	}
 
 	@Test
+	public void testOneIfRatherThanDuplicateBlocksThatFallThroughCleanUp() throws Exception {
+		CleanUpRefactoring cleanUpRefactoring= new CleanUpRefactoring();
+		addAllCUs(cleanUpRefactoring, MyTestSetup.fJProject1.getChildren());
+
+		Map<String, String> node= getNullSettings();
+
+		node.put(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH, CleanUpOptions.TRUE);
+
+		storeSettings(node);
+
+		cleanUpRefactoring.addCleanUp(new OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp());
+
+		doCleanUp(cleanUpRefactoring);
+	}
+
+	@Test
 	public void testComparingOnCriteriaCleanUp() throws Exception {
 		CleanUpRefactoring cleanUpRefactoring= new CleanUpRefactoring();
 		addAllCUs(cleanUpRefactoring, MyTestSetup.fJProject1.getChildren());
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java
index 0942995..70d0cef 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest.java
@@ -18258,6 +18258,327 @@
 	}
 
 	@Test
+	public void testOneIfRatherThanDuplicateBlocksThatFallThrough() throws Exception {
+		// Given
+		IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+		String given= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    public void mergeConditionsWithReturn(int i1) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if (i1 == 0) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        // Keep this comment too\n" //
+				+ "        if (i1 == 1) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeConditionsWithThrow(int i1) throws Exception {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if (i1 == 0) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            i1--;\n" //
+				+ "            throw new Exception();\n" //
+				+ "        }\n" //
+				+ "        // Keep this comment too\n" //
+				+ "        if (i1 == 1) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            --i1;\n" //
+				+ "            throw new Exception();\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeConditionsWithContinue() {\n" //
+				+ "        for (int i1 = 0; i1 < 10; i1++) {\n" //
+				+ "            // Keep this comment\n" //
+				+ "            if (i1 == 0) {\n" //
+				+ "                System.out.println(\"The same code\");\n" //
+				+ "                i1++;\n" //
+				+ "                continue;\n" //
+				+ "            }\n" //
+				+ "            // Keep this comment too\n" //
+				+ "            if (i1 == 1) {\n" //
+				+ "                System.out.println(\"The same code\");\n" //
+				+ "                ++i1;\n" //
+				+ "                continue;\n" //
+				+ "            }\n" //
+				+ "            System.out.println(\"Next code\");\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Another code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeConditionsWithBreak() {\n" //
+				+ "        for (int i1 = 0; i1 < 10; i1++) {\n" //
+				+ "            // Keep this comment\n" //
+				+ "            if (i1 == 0) {\n" //
+				+ "                System.out.println(\"The same code\");\n" //
+				+ "                i1++;\n" //
+				+ "                break;\n" //
+				+ "            }\n" //
+				+ "            // Keep this comment too\n" //
+				+ "            if (i1 == 1) {\n" //
+				+ "                System.out.println(\"The same code\");\n" //
+				+ "                i1 = i1 + 1;\n" //
+				+ "                break;\n" //
+				+ "            }\n" //
+				+ "            System.out.println(\"Next code\");\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Another code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeConditionsWithReturnAndThrow(int i1, int i2) throws Exception {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if (i1 == 0) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            if (i2 == 0) {\n" //
+				+ "                return;\n" //
+				+ "            } else {\n" //
+				+ "                throw new Exception(\"Error #\" + i1++);\n" //
+				+ "            }\n" //
+				+ "        }\n" //
+				+ "        if (i1 == 1) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            if (i2 == 0) {\n" //
+				+ "                return;\n" //
+				+ "            } else {\n" //
+				+ "                throw new Exception(\"Error #\" + i1++);\n" //
+				+ "            }\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeSeveralConditions(int i1) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if (i1 == 0) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        if (i1 == 1) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        if (i1 == 2) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        if (i1 == 3) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeORConditions(boolean isValid, boolean isActive, boolean isEnabled, boolean isFound) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if (isValid || isActive) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        if (isEnabled || isFound) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "}\n";
+
+		String expected= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    public void mergeConditionsWithReturn(int i1) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        // Keep this comment too\n" //
+				+ "        if ((i1 == 0) || (i1 == 1)) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeConditionsWithThrow(int i1) throws Exception {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        // Keep this comment too\n" //
+				+ "        if ((i1 == 0) || (i1 == 1)) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            --i1;\n" //
+				+ "            throw new Exception();\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeConditionsWithContinue() {\n" //
+				+ "        for (int i1 = 0; i1 < 10; i1++) {\n" //
+				+ "            // Keep this comment\n" //
+				+ "            // Keep this comment too\n" //
+				+ "            if ((i1 == 0) || (i1 == 1)) {\n" //
+				+ "                System.out.println(\"The same code\");\n" //
+				+ "                ++i1;\n" //
+				+ "                continue;\n" //
+				+ "            }\n" //
+				+ "            System.out.println(\"Next code\");\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Another code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeConditionsWithBreak() {\n" //
+				+ "        for (int i1 = 0; i1 < 10; i1++) {\n" //
+				+ "            // Keep this comment\n" //
+				+ "            // Keep this comment too\n" //
+				+ "            if ((i1 == 0) || (i1 == 1)) {\n" //
+				+ "                System.out.println(\"The same code\");\n" //
+				+ "                i1 = i1 + 1;\n" //
+				+ "                break;\n" //
+				+ "            }\n" //
+				+ "            System.out.println(\"Next code\");\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Another code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeConditionsWithReturnAndThrow(int i1, int i2) throws Exception {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if ((i1 == 0) || (i1 == 1)) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            if (i2 == 0) {\n" //
+				+ "                return;\n" //
+				+ "            } else {\n" //
+				+ "                throw new Exception(\"Error #\" + i1++);\n" //
+				+ "            }\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeSeveralConditions(int i1) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if ((i1 == 0) || (i1 == 1) || (i1 == 2)\n" //
+				+ "                || (i1 == 3)) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void mergeORConditions(boolean isValid, boolean isActive, boolean isEnabled, boolean isFound) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if (isValid || isActive || isEnabled || isFound) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "}\n";
+
+		// When
+		ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null);
+		enable(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH);
+
+		// Then
+		assertNotEquals("The class must be changed", given, expected);
+		assertRefactoringResultAsExpected(new ICompilationUnit[] { cu }, new String[] { expected }, new HashSet<>(Arrays.asList(MultiFixMessages.OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp_description)));
+	}
+
+	@Test
+	public void testDoNotUseOneIfRatherThanDuplicateBlocksThatFallThrough() throws Exception {
+		IPackageFragment pack= fSourceFolder.createPackageFragment("test1", false, null);
+		String sample= "" //
+				+ "package test1;\n" //
+				+ "\n" //
+				+ "public class E {\n" //
+				+ "    public void doNotMergeConditionsWithConditionalReturn(int i1, int i2) {\n" //
+				+ "        if (i1 == 0) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            if (i2 == 0) {\n" //
+				+ "                return;\n" //
+				+ "            }\n" //
+				+ "        }\n" //
+				+ "        if (i1 == 1) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            if (i2 == 0) {\n" //
+				+ "                return;\n" //
+				+ "            }\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void doNotMergeMoreThanFourOperands(int i1) {\n" //
+				+ "        if ((i1 == 0) || (i1 == 1) || (i1 == 2) || (i1 == 3)) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        if (i1 == 4) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void doNotMergeConditionsWithoutJump(int i) {\n" //
+				+ "        if (i == 0) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "        }\n" //
+				+ "        if (i == 1) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void doNotMergeDifferentBlocks(int i) {\n" //
+				+ "        if (i == 0) {\n" //
+				+ "            System.out.println(\"A code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        if (i == 1) {\n" //
+				+ "            System.out.println(\"Another code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void doNotMergeConditionsWithElse(int i1, int counter) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if (i1 == 0) {\n" //
+				+ "            System.out.println(\"The count is: \" + counter++);\n" //
+				+ "            return;\n" //
+				+ "        } else {\n" //
+				+ "            System.out.println(\"The count is: \" + ++counter);\n" //
+				+ "        }\n" //
+				+ "        if (i1 == 1) {\n" //
+				+ "            System.out.println(\"The count is: \" + counter++);\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void doNotMergeConditionsWithAnotherElse(int i) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        if (i == 0) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        }\n" //
+				+ "        if (i == 1) {\n" //
+				+ "            System.out.println(\"The same code\");\n" //
+				+ "            return;\n" //
+				+ "        } else {\n" //
+				+ "            System.out.println(\"Another code\");\n" //
+				+ "        }\n" //
+				+ "        System.out.println(\"Next code\");\n" //
+				+ "    }\n" //
+				+ "}\n";
+		ICompilationUnit cu= pack.createCompilationUnit("E.java", sample, false, null);
+
+		enable(CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH);
+
+		assertRefactoringHasNoChange(new ICompilationUnit[] { cu });
+	}
+
+	@Test
 	public void testRegExPrecompilationInLambda() throws Exception {
 		IPackageFragment pack1= fSourceFolder.createPackageFragment("test1", false, null);
 		String sample= "" //
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java
index 33b4403..aa59a3d 100644
--- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java
+++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstantsOptions.java
@@ -168,6 +168,7 @@
 		options.setOption(STRICTLY_EQUAL_OR_DIFFERENT, CleanUpOptions.FALSE);
 		options.setOption(MERGE_CONDITIONAL_BLOCKS, CleanUpOptions.FALSE);
 		options.setOption(CONTROLFLOW_MERGE, CleanUpOptions.FALSE);
+		options.setOption(ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH, CleanUpOptions.TRUE);
 
 		// Java Features
 		options.setOption(USE_PATTERN_MATCHING_FOR_INSTANCEOF, CleanUpOptions.FALSE);
@@ -340,6 +341,7 @@
 		options.setOption(STRICTLY_EQUAL_OR_DIFFERENT, CleanUpOptions.FALSE);
 		options.setOption(MERGE_CONDITIONAL_BLOCKS, CleanUpOptions.FALSE);
 		options.setOption(CONTROLFLOW_MERGE, CleanUpOptions.FALSE);
+		options.setOption(ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH, CleanUpOptions.FALSE);
 
 		// Java Features
 		options.setOption(USE_PATTERN_MATCHING_FOR_INSTANCEOF, CleanUpOptions.FALSE);
diff --git a/org.eclipse.jdt.ui/plugin.xml b/org.eclipse.jdt.ui/plugin.xml
index c5d1b6d..eac0415 100644
--- a/org.eclipse.jdt.ui/plugin.xml
+++ b/org.eclipse.jdt.ui/plugin.xml
@@ -7403,9 +7403,14 @@
             runAfter="org.eclipse.jdt.ui.cleanup.merge_conditional_blocks">
       </cleanUp>
       <cleanUp
+            class="org.eclipse.jdt.internal.ui.fix.OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp"
+            id="org.eclipse.jdt.ui.one_if_rather_than_duplicate_blocks_that_fall_through"
+            runAfter="org.eclipse.jdt.ui.cleanup.controlflow_merge">
+      </cleanUp>
+      <cleanUp
             class="org.eclipse.jdt.internal.ui.fix.RedundantFallingThroughBlockEndCleanUp"
             id="org.eclipse.jdt.ui.cleanup.redundant_falling_through_block_end"
-            runAfter="org.eclipse.jdt.ui.cleanup.controlflow_merge">
+            runAfter="org.eclipse.jdt.ui.one_if_rather_than_duplicate_blocks_that_fall_through">
       </cleanUp>
       <cleanUp
             class="org.eclipse.jdt.internal.ui.fix.RedundantIfConditionCleanUp"
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp.java
new file mode 100644
index 0000000..445f3ff
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Fabrice TIERCELIN and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Fabrice TIERCELIN - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.jdt.core.manipulation.ICleanUpFixCore;
+
+import org.eclipse.jdt.ui.cleanup.CleanUpContext;
+import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
+import org.eclipse.jdt.ui.cleanup.CleanUpRequirements;
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+
+/**
+ * A fix that merges consecutive <code>if</code> statements with same code block that end with a jump statement:
+ * <ul>
+ * <li>It collapses 5 <code>if</code> statements maximum.</li>
+ * </ul>
+ */
+public class OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp extends AbstractCleanUp {
+	private OneIfRatherThanDuplicateBlocksThatFallThroughCleanUpCore coreCleanUp= new OneIfRatherThanDuplicateBlocksThatFallThroughCleanUpCore();
+
+	public OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp(final Map<String, String> options) {
+		setOptions(options);
+	}
+
+	public OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp() {
+	}
+
+	@Override
+	public void setOptions(final CleanUpOptions options) {
+		coreCleanUp.setOptions(options);
+	}
+
+	@Override
+	public CleanUpRequirements getRequirements() {
+		return new CleanUpRequirements(coreCleanUp.getRequirementsCore());
+	}
+
+	@Override
+	public ICleanUpFix createFix(final CleanUpContext context) throws CoreException {
+		ICleanUpFixCore fixCore= coreCleanUp.createFixCore(context);
+		return fixCore != null ? new CleanUpFixWrapper(fixCore) : null;
+	}
+
+	@Override
+	public String[] getStepDescriptions() {
+		return coreCleanUp.getStepDescriptions();
+	}
+
+	@Override
+	public String getPreview() {
+		return coreCleanUp.getPreview();
+	}
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java
index d46a6d13..d473f7e 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.java
@@ -180,6 +180,7 @@
 	public static String DuplicateCodeTabPage_CheckboxName_StrictlyEqualOrDifferent;
 	public static String DuplicateCodeTabPage_CheckboxName_MergeConditionalBlocks;
 	public static String DuplicateCodeTabPage_CheckboxName_ControlFlowMerge;
+	public static String DuplicateCodeTabPage_CheckboxName_OneIfRatherThanDuplicateBlocksThatFallThrough;
 	public static String DuplicateCodeTabPage_CheckboxName_RedundantFallingThroughBlockEnd;
 	public static String DuplicateCodeTabPage_CheckboxName_RedundantIfCondition;
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties
index 4eedd10..107645f 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/CleanUpMessages.properties
@@ -156,6 +156,7 @@
 DuplicateCodeTabPage_CheckboxName_StrictlyEqualOrDifferent=Use '==' or '^' on booleans
 DuplicateCodeTabPage_CheckboxName_MergeConditionalBlocks=Merge &conditions of if/else if/else that have the same blocks
 DuplicateCodeTabPage_CheckboxName_ControlFlowMerge=Pull down common code from if/else statement
+DuplicateCodeTabPage_CheckboxName_OneIfRatherThanDuplicateBlocksThatFallThrough=Single 'if' statement rather than duplicate blocks that fall through
 DuplicateCodeTabPage_CheckboxName_RedundantFallingThroughBlockEnd=Remove redundant end of block with &jump statement
 DuplicateCodeTabPage_CheckboxName_RedundantIfCondition=R&emove redundant if condition
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/DuplicateCodeTabPage.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/DuplicateCodeTabPage.java
index a60a314..62c1108 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/DuplicateCodeTabPage.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/cleanup/DuplicateCodeTabPage.java
@@ -23,6 +23,7 @@
 import org.eclipse.jdt.internal.ui.fix.AbstractCleanUp;
 import org.eclipse.jdt.internal.ui.fix.ControlFlowMergeCleanUp;
 import org.eclipse.jdt.internal.ui.fix.MergeConditionalBlocksCleanUp;
+import org.eclipse.jdt.internal.ui.fix.OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp;
 import org.eclipse.jdt.internal.ui.fix.OperandFactorizationCleanUp;
 import org.eclipse.jdt.internal.ui.fix.RedundantFallingThroughBlockEndCleanUp;
 import org.eclipse.jdt.internal.ui.fix.RedundantIfConditionCleanUp;
@@ -40,6 +41,7 @@
 				new StrictlyEqualOrDifferentCleanUp(values),
 				new MergeConditionalBlocksCleanUp(values),
 				new ControlFlowMergeCleanUp(values),
+				new OneIfRatherThanDuplicateBlocksThatFallThroughCleanUp(values),
 				new RedundantFallingThroughBlockEndCleanUp(values),
 				new RedundantIfConditionCleanUp(values)
 		};
@@ -64,6 +66,9 @@
 		final CheckboxPreference controlFlowMerge= createCheckboxPref(duplicateGroup, numColumns, CleanUpMessages.DuplicateCodeTabPage_CheckboxName_ControlFlowMerge, CleanUpConstants.CONTROLFLOW_MERGE, CleanUpModifyDialog.FALSE_TRUE);
 		registerPreference(controlFlowMerge);
 
+		final CheckboxPreference oneIfRatherThanDuplicateBlocksThatFallThrough= createCheckboxPref(duplicateGroup, numColumns, CleanUpMessages.DuplicateCodeTabPage_CheckboxName_OneIfRatherThanDuplicateBlocksThatFallThrough, CleanUpConstants.ONE_IF_RATHER_THAN_DUPLICATE_BLOCKS_THAT_FALL_THROUGH, CleanUpModifyDialog.FALSE_TRUE);
+		registerPreference(oneIfRatherThanDuplicateBlocksThatFallThrough);
+
 		final CheckboxPreference redundantFallingThroughBlockEnd= createCheckboxPref(duplicateGroup, numColumns, CleanUpMessages.DuplicateCodeTabPage_CheckboxName_RedundantFallingThroughBlockEnd, CleanUpConstants.REDUNDANT_FALLING_THROUGH_BLOCK_END, CleanUpModifyDialog.FALSE_TRUE);
 		registerPreference(redundantFallingThroughBlockEnd);