Bug 570413
- Check the criteria is a comparable object
- Add JavaDoc
Change-Id: I989be4f006586059b190d4fd9b299194454a2e75
Signed-off-by: Fabrice Tiercelin <fabrice.tiercelin@yahoo.fr>
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/ControlWorkflowMatcher.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/ControlWorkflowMatcher.java
index c16f1a6..4ef642a 100644
--- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/ControlWorkflowMatcher.java
+++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/util/ControlWorkflowMatcher.java
@@ -35,6 +35,92 @@
/**
* Implementation of the control workflow builder.
+ *
+ * The aim is to match a conditional part of code like:
+ *
+ * <pre>
+ * if (c1) {
+ * if (c2) {
+ * return A;
+ * } else {
+ * return B;
+ * }
+ * } else {
+ * if (c3) {
+ * return C;
+ * } else {
+ * return D;
+ * }
+ * }
+ * </pre>
+ *
+ * Any cases should be handled (no remaining cases). It is expressed this way
+ * <ul>
+ * <li>One case (c1, c2) goes to A</li>
+ * <li>One case (c1, not c2) goes to B</li>
+ * <li>One case (not c1, c3) goes to C</li>
+ * <li>One case (not c1, not c3) goes to D</li>
+ * </ul>
+ *
+ * It can handle as many conditions as you want.
+ * The conditions and the expressions are analyzed as ordinary matcher using <code>org.eclipse.jdt.internal.corext.dom.ASTSemanticMatcher</code>.
+ * All the remaining part of the structure may have lots of different forms:
+ *
+ * <pre>
+ * if (c1 && c2) {
+ * return A;
+ * } else if (c1 && not c2) {
+ * return B;
+ * } else if (not c1 && not c3) {
+ * return D;
+ * } else if (not c1 && c3) {
+ * return C;
+ * }
+ * </pre>
+ *
+ * <pre>
+ * if (c1) {
+ * if (c2) {
+ * return A;
+ * }
+ * return B;
+ * } else {
+ * if (c3) {
+ * return C;
+ * }
+ * return D;
+ * }
+ * </pre>
+ *
+ * <pre>
+ * if (c1) {
+ * if (not c2) {
+ * return B;
+ * } else {
+ * return A;
+ * }
+ * } else {
+ * if (not c3) {
+ * return D;
+ * } else {
+ * return C;
+ * }
+ * }
+ * </pre>
+ *
+ * <pre>
+ * if (c1) {
+ * return c2 ? A : B;
+ * } else {
+ * return c3 ? C :D;
+ * }
+ *
+ * if (not c1) {
+ * return c3 ? C :D;
+ * }
+ *
+ * return not c2 ? A : B;
+ * </pre>
*/
public final class ControlWorkflowMatcher implements ControlWorkflowMatcherCompletable, ControlWorkflowMatcherRunnable {
/**
diff --git a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java
index d1c1db8..4a7946a 100644
--- a/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java
+++ b/org.eclipse.jdt.ui.tests/ui/org/eclipse/jdt/ui/tests/quickfix/CleanUpTest1d8.java
@@ -1591,6 +1591,13 @@
+ "import java.util.Locale;\n" //
+ "\n" //
+ "public class E {\n" //
+ + " private Comparator<Date> refactorField = new Comparator<Date>() {\n" //
+ + " @Override\n" //
+ + " public int compare(Date o1, Date o2) {\n" //
+ + " return o1.toString().compareTo(o2.toString());\n" //
+ + " }\n" //
+ + " };\n" //
+ + "\n" //
+ " public List<Date> useMethodRef(List<Date> listToSort) {\n" //
+ " // Keep this comment\n" //
+ " Comparator<Date> comparator = new Comparator<Date>() {\n" //
@@ -1988,6 +1995,8 @@
+ "import java.util.Locale;\n" //
+ "\n" //
+ "public class E {\n" //
+ + " private Comparator<Date> refactorField = Comparator.comparing(Date::toString);\n" //
+ + "\n" //
+ " public List<Date> useMethodRef(List<Date> listToSort) {\n" //
+ " // Keep this comment\n" //
+ " Comparator<Date> comparator = Comparator.comparing(Date::toString);\n" //
@@ -2243,6 +2252,21 @@
+ " return comparator;\n" //
+ " }\n" //
+ "\n" //
+ + " public int compareTo(E anc) {\n" //
+ + " return 0;\n" //
+ + " }\n" //
+ + "\n" //
+ + " public E getNewInstance() {\n" //
+ + " return new E();\n" //
+ + " }\n" //
+ + "\n" //
+ + " private Comparator<E> doNotRefactorNotComparableObjects = new Comparator<E>() {\n" //
+ + " @Override\n" //
+ + " public int compare(E o1, E o2) {\n" //
+ + " return o1.getNewInstance().compareTo(o2.getNewInstance());\n" //
+ + " }\n" //
+ + " };\n" //
+ + "\n" //
+ " public Comparator<Date> doNotRemoveSecondaryMethod(List<Date> listToSort) {\n" //
+ " Comparator<Date> comparator = new Comparator<Date>() {\n" //
+ "\n" //
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/ComparingOnCriteriaCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/ComparingOnCriteriaCleanUp.java
index bc6b863..f7bfd73 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/ComparingOnCriteriaCleanUp.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/ComparingOnCriteriaCleanUp.java
@@ -353,6 +353,26 @@
return true;
}
+ private boolean isComparable(ITypeBinding classBinding) {
+ if ("java.lang.Comparable".equals(classBinding.getErasure().getQualifiedName())) { //$NON-NLS-1$
+ return true;
+ }
+
+ ITypeBinding superClass= classBinding.getSuperclass();
+
+ if (superClass != null && isComparable(superClass)) {
+ return true;
+ }
+
+ for (ITypeBinding binding : classBinding.getInterfaces()) {
+ if (isComparable(binding)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private boolean isReturnedExpressionToRefactor(final Expression returnExpression, final AtomicReference<Expression> criteria,
final AtomicBoolean isForward, final SimpleName name1,
final SimpleName name2) {
@@ -368,7 +388,7 @@
if (compareToMethod != null && compareToMethod.getExpression() != null) {
ITypeBinding comparisonType= compareToMethod.getExpression().resolveTypeBinding();
- if (comparisonType != null) {
+ if (comparisonType != null && isComparable(comparisonType)) {
if (compareToMethod.getExpression() != null
&& ASTNodes.usesGivenSignature(compareToMethod, comparisonType.getQualifiedName(), "compareTo", comparisonType.getQualifiedName())) { //$NON-NLS-1$
return isRefactorComparisonToRefactor(criteria, isForward, name1, name2, compareToMethod.getExpression(), (Expression) compareToMethod.arguments().get(0));