diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java index 6a9599650af5..8a2cac28af70 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/CFGBuilder.java @@ -358,7 +358,7 @@ public class CFGBuilder { * * @return this builder */ - public CFGBuilder boxUnbox(PsiExpression expression, PsiType expectedType) { + public CFGBuilder boxUnbox(@NotNull PsiExpression expression, PsiType expectedType) { myAnalyzer.generateBoxingUnboxingInstructionFor(expression, expectedType); return this; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/MapUpdateInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/MapUpdateInliner.java index 4c30fca8445e..e44805dd00df 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/MapUpdateInliner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/MapUpdateInliner.java @@ -11,6 +11,7 @@ import com.intellij.psi.PsiExpression; import com.intellij.psi.PsiMethodCallExpression; import com.intellij.psi.PsiType; import com.siyeh.ig.callMatcher.CallMatcher; +import com.siyeh.ig.psiutils.ExpectedTypeUtils; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -67,6 +68,7 @@ public class MapUpdateInliner implements CallInliner { .pushExpression(key) .pop() .pushExpression(value) + .boxUnbox(value, ExpectedTypeUtils.findExpectedType(value, false)) .checkNotNull(value, NullabilityProblemKind.passingNullableToNotNullParameter) .evaluateFunction(function) .pushUnknown() diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java index 5b3de6b66d8c..98bc6fd1807a 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java @@ -26,10 +26,7 @@ import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.JavaConstantExpressionEvaluator; -import com.intellij.psi.util.InheritanceUtil; -import com.intellij.psi.util.PropertyUtilBase; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.psi.util.PsiUtil; +import com.intellij.psi.util.*; import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.psiutils.ClassUtils; @@ -283,19 +280,19 @@ public class DfaExpressionFactory { } @NotNull - private DfaValue getAdvancedExpressionDfaValue(@Nullable PsiExpression expression) { + private DfaValue getAdvancedExpressionDfaValue(@Nullable PsiExpression expression, @Nullable PsiType targetType) { if (expression == null) return DfaUnknownValue.getInstance(); DfaValue value = getExpressionDfaValue(expression); if (value != null) { - return value; + return boxUnbox(value, targetType); } if (expression instanceof PsiConditionalExpression) { - return getAdvancedExpressionDfaValue(((PsiConditionalExpression)expression).getThenExpression()).union( - getAdvancedExpressionDfaValue(((PsiConditionalExpression)expression).getElseExpression())); + return getAdvancedExpressionDfaValue(((PsiConditionalExpression)expression).getThenExpression(), targetType).union( + getAdvancedExpressionDfaValue(((PsiConditionalExpression)expression).getElseExpression(), targetType)); } PsiType type = expression.getType(); if (type instanceof PsiPrimitiveType) return DfaUnknownValue.getInstance(); - return myFactory.createTypeValue(type, NullabilityUtil.getExpressionNullability(expression)); + return boxUnbox(myFactory.createTypeValue(type, NullabilityUtil.getExpressionNullability(expression)), targetType); } @NotNull @@ -311,18 +308,37 @@ public class DfaExpressionFactory { DfaVariableValue arrayDfaVar = (DfaVariableValue)array; PsiModifierListOwner arrayPsiVar = arrayDfaVar.getPsiVariable(); if (!(arrayPsiVar instanceof PsiVariable)) return DfaUnknownValue.getInstance(); + PsiType arrayType = ((PsiVariable)arrayPsiVar).getType(); + PsiType targetType = arrayType instanceof PsiArrayType ? ((PsiArrayType)arrayType).getComponentType() : null; PsiExpression[] elements = ExpressionUtils.getConstantArrayElements((PsiVariable)arrayPsiVar); if (elements == null || elements.length == 0) return DfaUnknownValue.getInstance(); indexSet = indexSet.intersect(LongRangeSet.range(0, elements.length - 1)); if (indexSet.isEmpty() || indexSet.max() - indexSet.min() > 100) return DfaUnknownValue.getInstance(); return LongStreamEx.of(indexSet.stream()) - .mapToObj(idx -> getAdvancedExpressionDfaValue(elements[(int)idx])) + .mapToObj(idx -> getAdvancedExpressionDfaValue(elements[(int)idx], targetType)) .prefix(DfaValue::union) .takeWhileInclusive(value -> value != DfaUnknownValue.getInstance()) .reduce((a, b) -> b) .orElse(DfaUnknownValue.getInstance()); } + private DfaValue boxUnbox(DfaValue value, PsiType type) { + if (TypeConversionUtil.isPrimitiveWrapper(type)) { + if (value instanceof DfaConstValue || value instanceof DfaUnboxedValue || + (value instanceof DfaVariableValue && TypeConversionUtil.isPrimitiveAndNotNull(((DfaVariableValue)value).getVariableType()))) { + DfaValue boxed = myFactory.getBoxedFactory().createBoxed(value); + return boxed == null ? DfaUnknownValue.getInstance() : boxed; + } + } + if (TypeConversionUtil.isPrimitiveAndNotNull(type)) { + if (value instanceof DfaBoxedValue || + (value instanceof DfaVariableValue && TypeConversionUtil.isPrimitiveWrapper(((DfaVariableValue)value).getVariableType()))) { + return myFactory.getBoxedFactory().createUnboxed(value); + } + } + return value; + } + @Contract("null, _ -> null") @Nullable public DfaValue getArrayElementValue(DfaValue array, int index) { @@ -335,7 +351,7 @@ public class DfaExpressionFactory { if (arrayPsiVar instanceof PsiVariable) { PsiExpression constantArrayElement = ExpressionUtils.getConstantArrayElement((PsiVariable)arrayPsiVar, index); if (constantArrayElement != null) { - return getAdvancedExpressionDfaValue(constantArrayElement); + return getAdvancedExpressionDfaValue(constantArrayElement, componentType); } } ArrayElementSource indexVariable = getArrayIndexVariable(index); diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/BoxUnboxArrayElement.java b/java/java-tests/testData/inspection/dataFlow/fixture/BoxUnboxArrayElement.java new file mode 100644 index 000000000000..658d1e72457e --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/BoxUnboxArrayElement.java @@ -0,0 +1,14 @@ +class Test { + private final static Integer[] DATA = {119, 7, 3}; + private final static int[] DATA2 = {119, 7, 3}; + + void test() { + for(int i=0; i map, String key) { + map.merge(key, 1, (i1, i2) -> i1+1); + } } diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java index 614c2b188021..50ffb9e7eff7 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java @@ -620,4 +620,5 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { public void testNanComparisonWrong() { doTest(); } public void testConstantMethods() { doTest(); } public void testPolyadicEquality() { doTest(); } + public void testBoxUnboxArrayElement() { doTest(); } }