diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ObjectInstantiationInEqualsHashCodeInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ObjectInstantiationInEqualsHashCodeInspection.java index ebad27075f08..d5bd483c37da 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ObjectInstantiationInEqualsHashCodeInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/performance/ObjectInstantiationInEqualsHashCodeInspection.java @@ -1,6 +1,8 @@ -// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.siyeh.ig.performance; +import com.intellij.codeInspection.dataFlow.*; +import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.siyeh.InspectionGadgetsBundle; @@ -13,6 +15,8 @@ import com.siyeh.ig.psiutils.TypeUtils; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; +import java.util.List; + /** * @author Bas Leijdekkers */ @@ -45,7 +49,7 @@ public class ObjectInstantiationInEqualsHashCodeInspection extends BaseInspectio @Override public void visitExpression(PsiExpression expression) { - if (!ExpressionUtils.isAutoBoxed(expression) || !isInsideEqualsOrHashCode(expression)) { + if (!ExpressionUtils.isAutoBoxed(expression) || isAutoBoxingFromCache(expression) || !isInsideEqualsOrHashCode(expression)) { return; } final PsiType expectedType = ExpectedTypeUtils.findExpectedType(expression, false, true); @@ -67,24 +71,29 @@ public class ObjectInstantiationInEqualsHashCodeInspection extends BaseInspectio @Override public void visitMethodCallExpression(PsiMethodCallExpression expression) { - final PsiReferenceExpression methodExpression = expression.getMethodExpression(); final PsiMethod method = expression.resolveMethod(); if (method == null) { return; } - if (method.isVarArgs()) { + List contracts = JavaMethodContractUtil.getMethodContracts(method); + ContractReturnValue contractValue = JavaMethodContractUtil.getNonFailingReturnValue(contracts); + if (ContractReturnValue.returnNew().equals(contractValue)) { if (!isInsideEqualsOrHashCode(expression)) { return; } - registerError(expression, expression, "varargs call"); + registerMethodCallError(expression, expression); } - else { - final String name = methodExpression.getReferenceName(); - if (!"valueOf".equals(name)) { + else if (method.isVarArgs()) { + if (!isInsideEqualsOrHashCode(expression)) { return; } - final PsiExpressionList argumentList = expression.getArgumentList(); - final PsiExpression[] expressions = argumentList.getExpressions(); + registerMethodCallError(expression, expression, "varargs call"); + } + else { + if (!"valueOf".equals(method.getName())) { + return; + } + final PsiExpression[] expressions = expression.getArgumentList().getExpressions(); if (expressions.length != 1) { return; } @@ -93,18 +102,41 @@ public class ObjectInstantiationInEqualsHashCodeInspection extends BaseInspectio return; } final String qualifiedName = aClass.getQualifiedName(); - if (!CommonClassNames.JAVA_LANG_SHORT.equals(qualifiedName) && !CommonClassNames.JAVA_LANG_INTEGER.equals(qualifiedName) && - !CommonClassNames.JAVA_LANG_LONG.equals(qualifiedName) && !CommonClassNames.JAVA_LANG_DOUBLE.equals(qualifiedName) && - !CommonClassNames.JAVA_LANG_FLOAT.equals(qualifiedName) && !CommonClassNames.JAVA_LANG_CHARACTER.equals(qualifiedName)) { - return; + if (CommonClassNames.JAVA_LANG_SHORT.equals(qualifiedName) || + CommonClassNames.JAVA_LANG_INTEGER.equals(qualifiedName) || + CommonClassNames.JAVA_LANG_LONG.equals(qualifiedName) || + CommonClassNames.JAVA_LANG_CHARACTER.equals(qualifiedName)) { + if (isAutoBoxingFromCache(expressions[0]) || !isInsideEqualsOrHashCode(expression)) { + return; + } + registerError(expression, expression); } - if (!isInsideEqualsOrHashCode(expression)) { - return; - } - registerError(expression, expression); } } + private static boolean isAutoBoxingFromCache(PsiExpression expression) { + final LongRangeSet range = CommonDataflow.getExpressionFact(expression, DfaFactType.RANGE); + if (range != null && !range.isEmpty() && range.min() >= -128 && range.max() <= 127) { + return true; + } + final Object value = ExpressionUtils.computeConstantExpression(expression); + if (value instanceof Number) { + final Number number = (Number)value; + final int l = number.intValue(); + if (l >= -128 && l <= 127) { + return true; + } + } + else if (value instanceof Character) { + final Character character = (Character)value; + final char c = character.charValue(); + if (c <= 127) { + return true; + } + } + return false; + } + @Override public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) { if (!(expression.getParent() instanceof PsiVariable)) { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/object_instantiation_in_equals_hash_code/ObjectInstantiationInEqualsHashCode.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/object_instantiation_in_equals_hash_code/ObjectInstantiationInEqualsHashCode.java index e88379f7a530..d9669b3bebe1 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/object_instantiation_in_equals_hash_code/ObjectInstantiationInEqualsHashCode.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/object_instantiation_in_equals_hash_code/ObjectInstantiationInEqualsHashCode.java @@ -1,5 +1,6 @@ import java.util.Arrays; import java.util.Comparator; +import java.util.regex.Pattern; class ObjectInstantiationInEqualsHashCode { @@ -45,23 +46,29 @@ class Y { @Override public int hashCode() { - Integer i = 1; - Short.valueOf((short) 1); + Integer i = 1; + i = 128; + Short.valueOf((short) 1); + Short.valueOf((short) 128); Byte.valueOf((byte) 1); // nope - Long.valueOf(1); + Long.valueOf(1); + Long.valueOf(128); Boolean.valueOf(true); // nope - Character.valueOf('a'); - Float.valueOf((float) 1.0); - Double.valueOf(1.0); + Character.valueOf('a'); + Character.valueOf('П'); + Float.valueOf((float) 1.0); + Double.valueOf(1.0); i++; int j = 1; j++; - int[] is = {j}; + int[] is = {127}; + Integer.valueOf(is[0]); int hashCode = 7; - java.util.Arrays.asList(); + java.util.Arrays.asList(); for (Object fooElement : fooList) { hashCode = 31 * hashCode + (fooElement == null ? 0 : fooElement.hashCode()); } + Pattern.compile("regex"); return hashCode; } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/ObjectInstantiationInEqualsHashCodeInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/ObjectInstantiationInEqualsHashCodeInspectionTest.java index c1b6c1a4adaf..d7fda834c7e8 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/ObjectInstantiationInEqualsHashCodeInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/ObjectInstantiationInEqualsHashCodeInspectionTest.java @@ -16,7 +16,9 @@ package com.siyeh.ig.performance; import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.testFramework.LightProjectDescriptor; import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** @@ -33,4 +35,10 @@ public class ObjectInstantiationInEqualsHashCodeInspectionTest extends LightInsp protected InspectionProfileEntry getInspection() { return new ObjectInstantiationInEqualsHashCodeInspection(); } + + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JAVA_9; + } } \ No newline at end of file