Bug 569726 - [cleanup] "Use '==' or '^' on booleans" rule should improve
redundant ternary expression

Change-Id: Id8285e00d367304ec67bc8ab6ee3f24e80c97a87
Signed-off-by: Fabrice Tiercelin <fabrice.tiercelin@yahoo.fr>
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 8389584..419e2ea 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
@@ -5811,6 +5811,26 @@
 				+ "        boolean newBoolean1 = (staticField > 0) && (staticField < 100) || (staticField <= 0) && (staticField >= 100);\n" //
 				+ "        boolean newBoolean2 = (staticField > 0) && (staticField < 100) || (staticField >= 100) && !(staticField > 0);\n" //
 				+ "    }\n" //
+				+ "\n" //
+				+ "    public void replaceTernaryWithPrimitiveTypes(boolean b1, boolean b2) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        boolean newBoolean1 = b1 ? !b2 : b2;\n" //
+				+ "        boolean newBoolean2 = b1 ? b2 : !b2;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void replaceTernaryWithExpressions(int i1, int i2, int i3, int i4) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        boolean newBoolean1 = (i1 == i2) ? !(i3 == i4) : (i3 == i4);\n" //
+				+ "        boolean newBoolean2 = (i1 == i2) ? (i3 <= i4) : !(i4 >= i3);\n" //
+				+ "        boolean newBoolean3 = (i1 == i2) ? (i3 != i4) : (i3 == i4);\n" //
+				+ "        boolean newBoolean4 = (i1 == i2) ? (i3 < i4) : (i4 <= i3);\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void replaceTernaryWithFields() {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        boolean newBoolean1 = (staticField > 0) ? (staticField < 100) : (staticField >= 100);\n" //
+				+ "        boolean newBoolean2 = (staticField > 0) ? (staticField < 100) : !(staticField < 100);\n" //
+				+ "    }\n" //
 				+ "}\n";
 		ICompilationUnit cu= pack.createCompilationUnit("E.java", given, false, null);
 
@@ -5859,6 +5879,26 @@
 				+ "        boolean newBoolean1 = (staticField > 0) == (staticField < 100);\n" //
 				+ "        boolean newBoolean2 = (staticField > 0) == (staticField < 100);\n" //
 				+ "    }\n" //
+				+ "\n" //
+				+ "    public void replaceTernaryWithPrimitiveTypes(boolean b1, boolean b2) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        boolean newBoolean1 = b1 ^ b2;\n" //
+				+ "        boolean newBoolean2 = b1 == b2;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void replaceTernaryWithExpressions(int i1, int i2, int i3, int i4) {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        boolean newBoolean1 = (i1 == i2) ^ (i3 == i4);\n" //
+				+ "        boolean newBoolean2 = (i1 == i2) == (i3 <= i4);\n" //
+				+ "        boolean newBoolean3 = (i1 == i2) == (i3 != i4);\n" //
+				+ "        boolean newBoolean4 = (i1 == i2) == (i3 < i4);\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void replaceTernaryWithFields() {\n" //
+				+ "        // Keep this comment\n" //
+				+ "        boolean newBoolean1 = (staticField > 0) == (staticField < 100);\n" //
+				+ "        boolean newBoolean2 = (staticField > 0) == (staticField < 100);\n" //
+				+ "    }\n" //
 				+ "}\n";
 
 		assertNotEquals("The class must be changed", given, expected);
@@ -5918,6 +5958,22 @@
 				+ "        boolean newBoolean2 = b1 && new SideEffect() instanceof SideEffect\n" //
 				+ "                || !b1 && !(new SideEffect() instanceof SideEffect);\n" //
 				+ "    }\n" //
+				+ "\n" //
+				+ "    public boolean doNotReplaceNullableObjects(Boolean booleanObject1, Boolean booleanObject2) {\n" //
+				+ "        return booleanObject1 ? booleanObject2 : !booleanObject2;\n" //
+				+ "    }\n" //
+				+ "\n" //
+				+ "    public void doNotReplaceTernaryWithIncrements(int i1, int i2, int i3, int i4) {\n" //
+				+ "        boolean newBoolean1 = (i1 == i2) ? !(i3 == i4++) : (i3 == i4++);\n" //
+				+ "        boolean newBoolean2 = (i1 == i2) ? !(i3 == ++i4) : (i3 == ++i4);\n" //
+				+ "        boolean newBoolean3 = (i1 == i2) ? !(i3 == i4--) : (i3 == i4--);\n" //
+				+ "        boolean newBoolean4 = (i1 == i2) ? !(i3 == --i4) : (i3 == --i4);\n" //
+				+ "\n" //
+				+ "        boolean newBoolean5 = (i1 == i2) ? (i3 == i4++) : !(i3 == i4++);\n" //
+				+ "        boolean newBoolean6 = (i1 == i2) ? (i3 == ++i4) : !(i3 == ++i4);\n" //
+				+ "        boolean newBoolean7 = (i1 == i2) ? (i3 == i4--) : !(i3 == i4--);\n" //
+				+ "        boolean newBoolean8 = (i1 == i2) ? (i3 == --i4) : !(i3 == --i4);\n" //
+				+ "    }\n" //
 				+ "}\n";
 		ICompilationUnit cu= pack.createCompilationUnit("E.java", sample, false, null);
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/StrictlyEqualOrDifferentCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/StrictlyEqualOrDifferentCleanUp.java
index eb45e1b..4ce2401 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/StrictlyEqualOrDifferentCleanUp.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/StrictlyEqualOrDifferentCleanUp.java
@@ -28,6 +28,7 @@
 import org.eclipse.jdt.core.dom.AST;
 import org.eclipse.jdt.core.dom.ASTVisitor;
 import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.ConditionalExpression;
 import org.eclipse.jdt.core.dom.Expression;
 import org.eclipse.jdt.core.dom.InfixExpression;
 import org.eclipse.jdt.core.dom.PrefixExpression;
@@ -84,12 +85,16 @@
 		if (isEnabled(CleanUpConstants.STRICTLY_EQUAL_OR_DIFFERENT)) {
 			return "" //$NON-NLS-1$
 					+ "boolean newBoolean1 = isValid == (i > 0);\n" //$NON-NLS-1$
-					+ "boolean newBoolean2 = isValid ^ isEnabled;\n"; //$NON-NLS-1$
+					+ "boolean newBoolean2 = isValid ^ isEnabled;\n" //$NON-NLS-1$
+					+ "boolean newBoolean3 = isActive == (0 <= i);\n" //$NON-NLS-1$
+					+ "boolean newBoolean4 = isActive ^ isEnabled;\n"; //$NON-NLS-1$
 		}
 
 		return "" //$NON-NLS-1$
 				+ "boolean newBoolean1 = isValid && (i > 0) || !isValid && (i <= 0);\n" //$NON-NLS-1$
-				+ "boolean newBoolean2 = !isValid && isEnabled || isValid && !isEnabled;\n"; //$NON-NLS-1$
+				+ "boolean newBoolean2 = !isValid && isEnabled || isValid && !isEnabled;\n" //$NON-NLS-1$
+				+ "boolean newBoolean3 = isActive ? (0 <= i) : (i < 0);\n" //$NON-NLS-1$
+				+ "boolean newBoolean4 = !isActive ? isEnabled : !isEnabled;\n"; //$NON-NLS-1$
 	}
 
 	@Override
@@ -146,15 +151,35 @@
 				return true;
 			}
 
+			@Override
+			public boolean visit(final ConditionalExpression visited) {
+				if (ASTNodes.hasType(visited.getThenExpression(), boolean.class.getCanonicalName())
+						&& ASTNodes.hasType(visited.getElseExpression(), boolean.class.getCanonicalName())
+						&& ASTNodes.isPassive(visited.getThenExpression())
+						&& ASTNodes.isPassive(visited.getElseExpression())
+						&& ASTSemanticMatcher.INSTANCE.matchNegative(visited.getThenExpression(), visited.getElseExpression())) {
+					AtomicBoolean isFirstExpressionPositive= new AtomicBoolean();
+					AtomicBoolean isSecondExpressionPositive= new AtomicBoolean();
+
+					Expression firstBasicExpression= getBasisExpression(visited.getExpression(), isFirstExpressionPositive);
+					Expression secondBasicExpression= getBasisExpression(visited.getThenExpression(), isSecondExpressionPositive);
+
+					rewriteOperations.add(new StrictlyEqualOrDifferentOperation(visited, firstBasicExpression, secondBasicExpression, isFirstExpressionPositive.get() == isSecondExpressionPositive.get()));
+					return false;
+				}
+
+				return true;
+			}
+
 			private Expression getBasisExpression(final Expression originalExpression, final AtomicBoolean isExpressionPositive) {
 				PrefixExpression negateExpression= ASTNodes.as(originalExpression, PrefixExpression.class);
 
 				if (ASTNodes.hasOperator(negateExpression, PrefixExpression.Operator.NOT)) {
-					isExpressionPositive.set(false);
+					isExpressionPositive.lazySet(false);
 					return negateExpression.getOperand();
 				}
 
-				isExpressionPositive.set(true);
+				isExpressionPositive.lazySet(true);
 				return originalExpression;
 			}
 		});
@@ -183,12 +208,12 @@
 	}
 
 	private static class StrictlyEqualOrDifferentOperation extends CompilationUnitRewriteOperation {
-		private final InfixExpression visited;
+		private final Expression visited;
 		private final Expression firstExpression;
 		private final Expression secondExpression;
 		private final boolean isEquality;
 
-		public StrictlyEqualOrDifferentOperation(final InfixExpression visited, final Expression firstExpression, final Expression secondExpression, final boolean isEquality) {
+		public StrictlyEqualOrDifferentOperation(final Expression visited, final Expression firstExpression, final Expression secondExpression, final boolean isEquality) {
 			this.visited= visited;
 			this.firstExpression= firstExpression;
 			this.secondExpression= secondExpression;