diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/EqualsReplaceableByObjectsCallInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/EqualsReplaceableByObjectsCallInspection.java index e95e536ceb23..5d61b6dc09f6 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/EqualsReplaceableByObjectsCallInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/EqualsReplaceableByObjectsCallInspection.java @@ -30,7 +30,7 @@ import com.siyeh.ig.InspectionGadgetsFix; import com.siyeh.ig.PsiReplacementUtil; import com.siyeh.ig.psiutils.ExpressionUtils; import com.siyeh.ig.psiutils.ParenthesesUtils; -import com.siyeh.ig.psiutils.VariableAccessUtils; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,12 +100,8 @@ public class EqualsReplaceableByObjectsCallInspection extends BaseInspection { return; } final PsiExpression expression = (PsiExpression)element; - if (myEquals) { - PsiReplacementUtil.replaceExpressionAndShorten(expression, "java.util.Objects.equals(" + myName1 + "," + myName2 + ")"); - } - else { - PsiReplacementUtil.replaceExpressionAndShorten(expression, "!java.util.Objects.equals(" + myName1 + "," + myName2 + ")"); - } + final String expressionText = "java.util.Objects.equals(" + myName1 + "," + myName2 + ")"; + PsiReplacementUtil.replaceExpressionAndShorten(expression, myEquals ? expressionText : "!" + expressionText); } } @@ -123,6 +119,10 @@ public class EqualsReplaceableByObjectsCallInspection extends BaseInspection { @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) { + final String methodName = expression.getMethodExpression().getReferenceName(); + if (!HardcodedMethodConstants.EQUALS.equals(methodName)) { + return; + } final PsiElement maybeBinary = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class, PsiPrefixExpression.class); if (maybeBinary instanceof PsiBinaryExpression) { if (processNotNullCheck((PsiBinaryExpression)maybeBinary)) { @@ -130,69 +130,95 @@ public class EqualsReplaceableByObjectsCallInspection extends BaseInspection { } } if (!checkNotNull) { - final PsiVariable variable = ExpressionUtils.getVariable(expression.getMethodExpression().getQualifierExpression()); - if (variable == null) { + final PsiExpression qualifierExpression = getQualifierExpression(expression); + if (qualifierExpression == null) { return; } - final PsiVariable otherVariable = getArgumentFromEqualsCallOn(expression, variable); - if (otherVariable == null) { + final PsiExpression argumentExpression = getArgumentExpression(expression); + if (argumentExpression == null) { return; } - registerError(expression, variable.getName(), otherVariable.getName(), true); + registerError(expression, qualifierExpression.getText(), argumentExpression.getText(), true); } } + private PsiExpression getQualifierExpression(PsiMethodCallExpression expression) { + return ParenthesesUtils.stripParentheses(expression.getMethodExpression().getQualifierExpression()); + } + private boolean processNotNullCheck(PsiBinaryExpression expression) { final IElementType tokenType = expression.getOperationTokenType(); + final PsiExpression rightOperand = ParenthesesUtils.stripParentheses(expression.getROperand()); if (JavaTokenType.ANDAND.equals(tokenType)) { - final PsiVariable variable = ExpressionUtils.getVariableFromNullComparison(expression.getLOperand(), false); - if (variable == null) { - return false; - } - final PsiVariable otherVariable = getArgumentFromEqualsCallOn(expression.getROperand(), variable); - if (otherVariable == null) { - return false; - } - checkEqualityBefore(expression, true, variable, otherVariable); + return registerProblem(expression, rightOperand, true); } else if (JavaTokenType.OROR.equals(tokenType)) { - final PsiVariable variable = ExpressionUtils.getVariableFromNullComparison(expression.getLOperand(), true); - if (variable == null) { - return false; + if (rightOperand instanceof PsiPrefixExpression && + JavaTokenType.EXCL.equals(((PsiPrefixExpression)rightOperand).getOperationTokenType())) { + final PsiExpression negatedRightOperand = ParenthesesUtils.stripParentheses(((PsiPrefixExpression)rightOperand).getOperand()); + return registerProblem(expression, negatedRightOperand, false); } - final PsiExpression rhs = ParenthesesUtils.stripParentheses(expression.getROperand()); - if (!(rhs instanceof PsiPrefixExpression)) { - return false; - } - final PsiPrefixExpression prefixExpression = (PsiPrefixExpression)rhs; - if (!JavaTokenType.EXCL.equals(prefixExpression.getOperationTokenType())) { - return false; - } - final PsiVariable otherVariable = getArgumentFromEqualsCallOn(prefixExpression.getOperand(), variable); - if (otherVariable == null) { - return false; - } - checkEqualityBefore(expression, false, variable, otherVariable); } return true; } - private void checkEqualityBefore(PsiExpression expression, boolean equals, PsiVariable variable1, PsiVariable variable2) { - final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class); - if (parent instanceof PsiBinaryExpression) { - final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent; - if (PsiTreeUtil.isAncestor(binaryExpression.getROperand(), expression, false)) { - final PsiExpression lhs = binaryExpression.getLOperand(); - if (isEquality(lhs, equals, variable1, variable2)) { - registerError(binaryExpression, variable1.getName(), variable2.getName(), Boolean.valueOf(equals)); - return; + /** + * Match the patterns, and register the error if a pattern is matched: + *
+     * x==null || !x.equals(y)
+     * x!=null && x.equals(y)
+ * + * @return true if the pattern is matched + */ + private boolean registerProblem(PsiBinaryExpression expression, PsiExpression rightOperand, boolean equal) { + if ((rightOperand instanceof PsiMethodCallExpression)) { + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)rightOperand; + final PsiReferenceExpression nullCheckedExpression = + ExpressionUtils.getReferenceExpressionFromNullComparison(expression.getLOperand(), !equal); + final String nullCheckedName = getQualifiedVariableName(nullCheckedExpression); + if (nullCheckedName != null) { + final PsiExpression qualifierExpression = getQualifierExpression(methodCallExpression); + final String qualifierName = getQualifiedVariableName(qualifierExpression); + if (qualifierName != null && qualifierName.equals(nullCheckedName)) { + final PsiExpression argumentExpression = getArgumentExpression(methodCallExpression); + final String argumentName = getQualifiedVariableName(argumentExpression); + final PsiExpression expressionToReplace = + argumentName != null ? checkEqualityBefore(expression, equal, qualifierName, argumentName) : expression; + registerError(expressionToReplace, nullCheckedExpression.getText(), argumentExpression.getText(), Boolean.valueOf(equal)); + return true; } } } - registerError(expression, variable1.getName(), variable2.getName(), Boolean.valueOf(equals)); + return false; } - private boolean isEquality(PsiExpression expression, boolean equals, PsiVariable variable1, PsiVariable variable2) { + /** + * Match the left side of the patterns: + *
+     * x!=y && (x==null || !x.equals(y))
+     * x==y || (x!=null && x.equals(y))
+ * + * @return the expression matching the pattern, or the original expression if there's no match + */ + @Nullable + private PsiExpression checkEqualityBefore(PsiExpression expression, boolean equal, String qualifiedName1, String qualifiedName2) { + final PsiElement parent = PsiTreeUtil.skipParentsOfType(expression, PsiParenthesizedExpression.class); + if (parent instanceof PsiBinaryExpression) { + final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)parent; + final IElementType tokenType = binaryExpression.getOperationTokenType(); + if (equal && JavaTokenType.OROR.equals(tokenType) || !equal && JavaTokenType.ANDAND.equals(tokenType)) { + if (PsiTreeUtil.isAncestor(binaryExpression.getROperand(), expression, false)) { + final PsiExpression lhs = binaryExpression.getLOperand(); + if (isEquality(lhs, equal, qualifiedName1, qualifiedName2)) { + return binaryExpression; + } + } + } + } + return expression; + } + + private boolean isEquality(PsiExpression expression, boolean equals, String qualifiedName1, String qualifiedName2) { expression = ParenthesesUtils.stripParentheses(expression); if (!(expression instanceof PsiBinaryExpression)) { return false; @@ -208,33 +234,45 @@ public class EqualsReplaceableByObjectsCallInspection extends BaseInspection { return false; } } - final PsiExpression lhs = binaryExpression.getLOperand(); - final PsiExpression rhs = binaryExpression.getROperand(); - return (VariableAccessUtils.evaluatesToVariable(lhs, variable1) && VariableAccessUtils.evaluatesToVariable(rhs, variable2)) || - (VariableAccessUtils.evaluatesToVariable(lhs, variable2) && VariableAccessUtils.evaluatesToVariable(rhs, variable1)); - } - - private PsiVariable getArgumentFromEqualsCallOn(PsiExpression expression, PsiVariable variable) { - expression = ParenthesesUtils.stripParentheses(expression); - if (!(expression instanceof PsiMethodCallExpression)) { - return null; - } - final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression; - final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression(); - final String methodName = methodExpression.getReferenceName(); - if (!HardcodedMethodConstants.EQUALS.equals(methodName)) { - return null; - } - final PsiExpression qualifier = methodExpression.getQualifierExpression(); - if (!VariableAccessUtils.evaluatesToVariable(qualifier, variable)) { - return null; - } - final PsiExpressionList argumentList = methodCallExpression.getArgumentList(); - final PsiExpression[] expressions = argumentList.getExpressions(); - if (expressions.length != 1) { - return null; - } - return ExpressionUtils.getVariable(expressions[0]); + final PsiExpression leftOperand = ParenthesesUtils.stripParentheses(binaryExpression.getLOperand()); + final PsiExpression rightOperand = ParenthesesUtils.stripParentheses(binaryExpression.getROperand()); + final String leftName = getQualifiedVariableName(leftOperand); + final String rightName = getQualifiedVariableName(rightOperand); + return leftName != null && rightName != null && + (leftName.equals(qualifiedName1) && rightName.equals(qualifiedName2) || + leftName.equals(qualifiedName2) && rightName.equals(qualifiedName1)); } } + + private PsiExpression getArgumentExpression(PsiMethodCallExpression callExpression) { + final PsiExpression[] expressions = callExpression.getArgumentList().getExpressions(); + return expressions.length == 1 ? ParenthesesUtils.stripParentheses(expressions[0]) : null; + } + + /** + * Check if the expression is a variable name chain like "a.b.c" ("this" and "super" are allowed), and convert it into a qualified name + * + * @return the text representation of the variable chain (with parenthesis stripped), or {@code null} if it's not a variable chain + */ + @Nullable + private static String getQualifiedVariableName(@Nullable PsiExpression expression) { + if (expression instanceof PsiReferenceExpression) { + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression; + final String referenceName = referenceExpression.getReferenceName(); + if (referenceName != null && referenceExpression.resolve() instanceof PsiVariable) { + final PsiExpression qualifierExpression = ParenthesesUtils.stripParentheses(referenceExpression.getQualifierExpression()); + if (qualifierExpression == null) { + return referenceName; + } + final String qualifierName = getQualifiedVariableName(qualifierExpression); + return qualifierName != null ? qualifierName + "." + referenceName : null; + } + } + else if (expression instanceof PsiQualifiedExpression) { + final PsiJavaCodeReferenceElement qualifier = ((PsiQualifiedExpression)expression).getQualifier(); + final String name = expression instanceof PsiThisExpression ? "this" : "super"; + return qualifier != null ? qualifier.getQualifiedName() + "." + name : name; + } + return null; + } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java index 06d6d70a47c5..950c8e6119c3 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java @@ -600,6 +600,13 @@ public class ExpressionUtils { @Nullable public static PsiVariable getVariableFromNullComparison(PsiExpression expression, boolean equals) { + final PsiReferenceExpression referenceExpression = getReferenceExpressionFromNullComparison(expression, equals); + final PsiElement target = referenceExpression.resolve(); + return target instanceof PsiVariable ? (PsiVariable)target : null; + } + + @Nullable + public static PsiReferenceExpression getReferenceExpressionFromNullComparison(PsiExpression expression, boolean equals) { expression = ParenthesesUtils.stripParentheses(expression); if (!(expression instanceof PsiPolyadicExpression)) { return null; @@ -620,26 +627,16 @@ public class ExpressionUtils { if (operands.length != 2) { return null; } + PsiExpression comparedToNull = null; if (PsiType.NULL.equals(operands[0].getType())) { - return getVariable(operands[1]); + comparedToNull = operands[1]; } else if (PsiType.NULL.equals(operands[1].getType())) { - return getVariable(operands[0]); + comparedToNull = operands[0]; } - return null; - } + comparedToNull = ParenthesesUtils.stripParentheses(comparedToNull); - public static PsiVariable getVariable(@Nullable PsiExpression expression) { - expression = ParenthesesUtils.stripParentheses(expression); - if (!(expression instanceof PsiReferenceExpression)) { - return null; - } - final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)expression; - final PsiElement target = referenceExpression.resolve(); - if (!(target instanceof PsiVariable)) { - return null; - } - return (PsiVariable)target; + return comparedToNull instanceof PsiReferenceExpression ? (PsiReferenceExpression)comparedToNull : null; } public static boolean isConcatenation(PsiElement element) { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument.after.java new file mode 100644 index 000000000000..f79fad6097c0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument.after.java @@ -0,0 +1,7 @@ +import java.util.Objects; + +class T { + static boolean same(String t, String s) { + return Objects.equals(s, t + "a"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument.java new file mode 100644 index 000000000000..aae5999d3032 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument.java @@ -0,0 +1,5 @@ +class T { + static boolean same(String t, String s) { + return s.equals(t + "a"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument2.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument2.after.java new file mode 100644 index 000000000000..f79fad6097c0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument2.after.java @@ -0,0 +1,7 @@ +import java.util.Objects; + +class T { + static boolean same(String t, String s) { + return Objects.equals(s, t + "a"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument2.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument2.java new file mode 100644 index 000000000000..bc4780982b91 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionArgument2.java @@ -0,0 +1,5 @@ +class T { + static boolean same(String t, String s) { + return s != null && s.equals(t + "a"); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionReciever.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionReciever.after.java new file mode 100644 index 000000000000..6b860f87b429 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionReciever.after.java @@ -0,0 +1,7 @@ +import java.util.Objects; + +class T { + static boolean same(String t, String s) { + return Objects.equals(t + "a", s); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionReciever.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionReciever.java new file mode 100644 index 000000000000..34935424f5fc --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ExpressionReciever.java @@ -0,0 +1,5 @@ +class T { + static boolean same(String t, String s) { + return (t + "a").equals(s); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongEquals.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongEquals.after.java new file mode 100644 index 000000000000..89dbe2e866b0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongEquals.after.java @@ -0,0 +1,9 @@ +import java.util.Objects; + +class T { + static class P { String n; } + + static boolean same(P a, P b) { + return Objects.equals(a.n, b.n); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongEquals.java new file mode 100644 index 000000000000..8bf64f2e1869 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongEquals.java @@ -0,0 +1,7 @@ +class T { + static class P { String n; } + + static boolean same(P a, P b) { + return a.n == b.n || a.n != null && a.n.equals(b.n); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongNotEquals.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongNotEquals.after.java new file mode 100644 index 000000000000..27b5495c1e8c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongNotEquals.after.java @@ -0,0 +1,9 @@ +import java.util.Objects; + +class T { + static class P { String n; } + + static boolean notSame(P a, P b) { + return !Objects.equals(a.n, b.n); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongNotEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongNotEquals.java new file mode 100644 index 000000000000..e8e91a0ca6f8 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/LongNotEquals.java @@ -0,0 +1,7 @@ +class T { + static class P { String n; } + + static boolean notSame(P a, P b) { + return a.n != b.n && (a.n == null || !a.n.equals(b.n)); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedArgument.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedArgument.after.java new file mode 100644 index 000000000000..645fabc98ddc --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedArgument.after.java @@ -0,0 +1,11 @@ +import java.util.Objects; + +class T { + static class A { + String s; + } + A a; + static boolean same(T t, String s) { + return Objects.equals(s, t.a.s); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedArgument.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedArgument.java new file mode 100644 index 000000000000..aac12a86faac --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedArgument.java @@ -0,0 +1,9 @@ +class T { + static class A { + String s; + } + A a; + static boolean same(T t, String s) { + return s.equals(t.a.s); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedReciever.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedReciever.after.java new file mode 100644 index 000000000000..e8dfb83d4efb --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedReciever.after.java @@ -0,0 +1,11 @@ +import java.util.Objects; + +class T { + static class A { + String s; + } + A a; + static boolean same(T t, String s) { + return Objects.equals(t.a.s, s); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedReciever.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedReciever.java new file mode 100644 index 000000000000..a0bceeab0215 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedReciever.java @@ -0,0 +1,9 @@ +class T { + static class A { + String s; + } + A a; + static boolean same(T t, String s) { + return t.a.s != null && t.a.s.equals(s); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedSuperEqual.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedSuperEqual.after.java new file mode 100644 index 000000000000..aa3904b837c6 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedSuperEqual.after.java @@ -0,0 +1,21 @@ +import java.util.Objects; + +class T { + String s; + + class A { + T t; + } + + class B extends A { + void check(final String s) { + new Runnable() { + @Override + public void run() { + boolean b = Objects.equals(B.super.t.s, s); + System.out.println(b); + } + }.run(); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedSuperEqual.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedSuperEqual.java new file mode 100644 index 000000000000..04473035ff79 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedSuperEqual.java @@ -0,0 +1,19 @@ +class T { + String s; + + class A { + T t; + } + + class B extends A { + void check(final String s) { + new Runnable() { + @Override + public void run() { + boolean b = (B.super.t.s) == s || (B.super.t.s) != null && (B.super.t).s.equals(s); + System.out.println(b); + } + }.run(); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedThisNotEqual.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedThisNotEqual.after.java new file mode 100644 index 000000000000..b1033d170156 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedThisNotEqual.after.java @@ -0,0 +1,10 @@ +import java.util.Objects; + +class T { + String s; + class A { + boolean notSame(String s) { + return !Objects.equals(T.this.s, s); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedThisNotEqual.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedThisNotEqual.java new file mode 100644 index 000000000000..d31c59b6b1c2 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/QualifiedThisNotEqual.java @@ -0,0 +1,8 @@ +class T { + String s; + class A { + boolean notSame(String s) { + return T.this.s != s && (T.this.s == null || !T.this.s.equals(s)); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortEquals.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortEquals.after.java new file mode 100644 index 000000000000..89dbe2e866b0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortEquals.after.java @@ -0,0 +1,9 @@ +import java.util.Objects; + +class T { + static class P { String n; } + + static boolean same(P a, P b) { + return Objects.equals(a.n, b.n); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortEquals.java new file mode 100644 index 000000000000..b73d8aace910 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortEquals.java @@ -0,0 +1,7 @@ +class T { + static class P { String n; } + + static boolean same(P a, P b) { + return a.n != null && a.n.equals(b.n); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortNotEquals.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortNotEquals.after.java new file mode 100644 index 000000000000..27b5495c1e8c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortNotEquals.after.java @@ -0,0 +1,9 @@ +import java.util.Objects; + +class T { + static class P { String n; } + + static boolean notSame(P a, P b) { + return !Objects.equals(a.n, b.n); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortNotEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortNotEquals.java new file mode 100644 index 000000000000..448876cf843a --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ShortNotEquals.java @@ -0,0 +1,7 @@ +class T { + static class P { String n; } + + static boolean notSame(P a, P b) { + return a.n == null || !a.n.equals(b.n); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleEquals.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleEquals.after.java new file mode 100644 index 000000000000..d71a4bd47561 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleEquals.after.java @@ -0,0 +1,7 @@ +import java.util.Objects; + +class T { + static boolean same(String t, String s) { + return Objects.equals(s, t); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleEquals.java new file mode 100644 index 000000000000..94de4bd54eba --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleEquals.java @@ -0,0 +1,5 @@ +class T { + static boolean same(String t, String s) { + return s.equals(t); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleNotEquals.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleNotEquals.after.java new file mode 100644 index 000000000000..4d7944100468 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleNotEquals.after.java @@ -0,0 +1,7 @@ +import java.util.Objects; + +class T { + static boolean notSame(String t, String s) { + return !Objects.equals(s, t); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleNotEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleNotEquals.java new file mode 100644 index 000000000000..e60629b0c73d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SimpleNotEquals.java @@ -0,0 +1,5 @@ +class T { + static boolean notSame(String t, String s) { + return !s.equals(t); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SuperEquals.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SuperEquals.after.java new file mode 100644 index 000000000000..481f5bf0b4f4 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SuperEquals.after.java @@ -0,0 +1,10 @@ +import java.util.Objects; + +class T { + String s; + static class X extends T { + boolean same(String s) { + return Objects.equals(super.s, s); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SuperEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SuperEquals.java new file mode 100644 index 000000000000..2a7a3a8a2d6d --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/SuperEquals.java @@ -0,0 +1,8 @@ +class T { + String s; + static class X extends T { + boolean same(String s) { + return super.s.equals(s); + } + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ThisEquals.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ThisEquals.after.java new file mode 100644 index 000000000000..b9a70ad038e0 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ThisEquals.after.java @@ -0,0 +1,8 @@ +import java.util.Objects; + +class T { + String s; + boolean same(String s) { + return Objects.equals(this.s, s); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ThisEquals.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ThisEquals.java new file mode 100644 index 000000000000..ace88e320f0c --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/migration/equals_replaceable_by_objects_call/ThisEquals.java @@ -0,0 +1,6 @@ +class T { + String s; + boolean same(String s) { + return this.s.equals(s); + } +} \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/equals_replaceable_by_objects_call/EqualsReplaceableByObjectsCall.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/equals_replaceable_by_objects_call/EqualsReplaceableByObjectsCall.java index 49b9afbef78f..b02a5a72e455 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/equals_replaceable_by_objects_call/EqualsReplaceableByObjectsCall.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/equals_replaceable_by_objects_call/EqualsReplaceableByObjectsCall.java @@ -8,4 +8,31 @@ class EqualsReplaceableByObjectsCall { void ignoreNullityCheck(Object a, Object b) { boolean c = a.equals(b); } + + void bar(T x, T y, T z) { + boolean b = !x.s.equals(y.s); + boolean c = x.s != null && x.s.equals(y.s); + boolean d = y.s != null && x.s.equals(y.s); + boolean e = x.s == null || !x.s.equals(y.s); + boolean f = x.s != y.s && (x.s == null || !x.s.equals(y.s)); + boolean g = x.s != y.s || (x.s == null || !x.s.equals(y.s)); + boolean h = x.s != y.s && (z.s == null || !x.s.equals(y.s)); + } + + void baz(T x, T y) { + boolean b = x.copy().equals(y.copy()); + boolean c = x != null && x.equals(y.copy()); + boolean d = x == null || !x.equals(y.copy()); + boolean e = x.copy() != null && x.copy().equals(y); + boolean f = x.copy() == null || !x.copy().equals(y); + boolean g = x.copy().s != null && x.copy().s.equals(y.s); + boolean h = x.copy().s == null || !x.copy().s.equals(y.s); + boolean i = x.s == y.copy().s || (x).s != null && (x.s).equals(y.copy().s); + boolean j = x.s != y.copy().s && ((x).s == null || !(x.s).equals(y.copy().s)); + } + + static class T { + String s; + T copy() { T t = new T(); t.s = s; return t; } + } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/equals_replaceable_by_objects_call/EqualsReplaceableByObjectsCallCheckNull.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/equals_replaceable_by_objects_call/EqualsReplaceableByObjectsCallCheckNull.java index 5d4f1fdbe924..2336a461c554 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/equals_replaceable_by_objects_call/EqualsReplaceableByObjectsCallCheckNull.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/migration/equals_replaceable_by_objects_call/EqualsReplaceableByObjectsCallCheckNull.java @@ -8,4 +8,31 @@ class EqualsReplaceableByObjectsCall { void ignoreNullityCheck(Object a, Object b) { boolean c = a.equals(b); } + + void bar(T x, T y, T z) { + boolean b = !x.s.equals(y.s); + boolean c = x.s != null && x.s.equals(y.s); + boolean d = y.s != null && x.s.equals(y.s); + boolean e = x.s == null || !x.s.equals(y.s); + boolean f = x.s != y.s && (x.s == null || !x.s.equals(y.s)); + boolean g = x.s != y.s || (x.s == null || !x.s.equals(y.s)); + boolean h = x.s != y.s && (z.s == null || !x.s.equals(y.s)); + } + + void baz(T x, T y) { + boolean b = x.copy().equals(y.copy()); + boolean c = x != null && x.equals(y.copy()); + boolean d = x == null || !x.equals(y.copy()); + boolean e = x.copy() != null && x.copy().equals(y); + boolean f = x.copy() == null || !x.copy().equals(y); + boolean g = x.copy().s != null && x.copy().s.equals(y.s); + boolean h = x.copy().s == null || !x.copy().s.equals(y.s); + boolean i = x.s == y.copy().s || (x).s != null && (x.s).equals(y.copy().s); + boolean j = x.s != y.copy().s && ((x).s == null || !(x.s).equals(y.copy().s)); + } + + static class T { + String s; + T copy() { T t = new T(); t.s = s; return t; } + } } \ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/migration/EqualsReplaceableByObjectsCallFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/migration/EqualsReplaceableByObjectsCallFixTest.java new file mode 100644 index 000000000000..9a4afb0acd87 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/migration/EqualsReplaceableByObjectsCallFixTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.siyeh.ig.fixes.migration; + +import com.intellij.pom.java.LanguageLevel; +import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.IGQuickFixesTestCase; +import com.siyeh.ig.migration.EqualsReplaceableByObjectsCallInspection; + +/** + * @author Pavel.Dolgov + */ +public class EqualsReplaceableByObjectsCallFixTest extends IGQuickFixesTestCase { + + public void testSimpleEquals() { doTest(); } + public void testSimpleNotEquals() { doTest(); } + + public void testQualifiedArgument() { doTest(); } + public void testQualifiedReciever() { doTest(); } + + public void testExpressionReciever() { doTest(); } + public void testExpressionArgument() { doTest(); } + public void testExpressionArgument2() { doTest(); } + + public void testLongEquals() { doTest(); } + public void testLongNotEquals() { doTest(); } + public void testShortEquals() { doTest(); } + public void testShortNotEquals() { doTest(); } + + public void testSuperEquals() { doTest(); } + public void testThisEquals() { doTest(); } + + public void testQualifiedThisNotEqual() { doTest(); } + public void testQualifiedSuperEqual() { doTest(); } + + @Override + protected void tuneFixture(JavaModuleFixtureBuilder builder) throws Exception { + builder.addJdk(IdeaTestUtil.getMockJdk18Path().getPath()) + .setLanguageLevel(LanguageLevel.JDK_1_7); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + myFixture.enableInspections(new EqualsReplaceableByObjectsCallInspection()); + myRelativePath = "migration/equals_replaceable_by_objects_call"; + myDefaultHint = InspectionGadgetsBundle.message("equals.replaceable.by.objects.call.quickfix"); + } +}