diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayAccessInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayAccessInstruction.java
index 14a0202b1cae..6a291711490e 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayAccessInstruction.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/java/inst/ArrayAccessInstruction.java
@@ -1,4 +1,4 @@
-// Copyright 2000-2021 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-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInspection.dataFlow.java.inst;
import com.intellij.codeInspection.dataFlow.TypeConstraint;
@@ -57,6 +57,7 @@ public class ArrayAccessInstruction extends ExpressionPushingInstruction {
}
else {
DfType type = TypeConstraint.fromDfType(stateBefore.getDfType(array)).getArrayComponentType();
+ type = type.meet(ArrayElementDescriptor.getArrayComponentType(array));
result = type == DfType.BOTTOM ? interpreter.getFactory().getUnknown() : interpreter.getFactory().fromDfType(type);
}
if (!(result instanceof DfaVariableValue) && array instanceof DfaVariableValue) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/jvm/descriptors/ArrayElementDescriptor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/jvm/descriptors/ArrayElementDescriptor.java
index da60dd99e5c3..bc27d2ab7164 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/jvm/descriptors/ArrayElementDescriptor.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/jvm/descriptors/ArrayElementDescriptor.java
@@ -7,10 +7,7 @@ import com.intellij.codeInspection.dataFlow.java.JavaDfaValueFactory;
import com.intellij.codeInspection.dataFlow.jvm.SpecialField;
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet;
import com.intellij.codeInspection.dataFlow.types.*;
-import com.intellij.codeInspection.dataFlow.value.DfaTypeValue;
-import com.intellij.codeInspection.dataFlow.value.DfaValue;
-import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
-import com.intellij.codeInspection.dataFlow.value.DfaVariableValue;
+import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.psi.*;
import com.intellij.util.ObjectUtils;
import com.siyeh.ig.psiutils.ExpressionUtils;
@@ -46,13 +43,22 @@ public final class ArrayElementDescriptor extends JvmVariableDescriptor {
DfaVariableValue qualifier = thisValue.getQualifier();
DfType dfType = getDfType(qualifier);
if (qualifier != null && dfType instanceof DfReferenceType) {
- PsiVarDescriptor descriptor = ObjectUtils.tryCast(qualifier.getDescriptor(), PsiVarDescriptor.class);
+ VariableDescriptor qualDescriptor = qualifier.getDescriptor();
+ int depth = 1;
+ while (qualDescriptor instanceof ArrayElementDescriptor) {
+ depth++;
+ qualifier = qualifier.getQualifier();
+ if (qualifier == null) break;
+ qualDescriptor = qualifier.getDescriptor();
+ }
+ PsiVarDescriptor descriptor = ObjectUtils.tryCast(qualDescriptor, PsiVarDescriptor.class);
if (descriptor != null) {
PsiType psiType = descriptor.getType(qualifier);
- if (psiType instanceof PsiArrayType) {
- PsiType componentType = ((PsiArrayType)psiType).getComponentType();
- return dfType.meet(DfaNullability.fromNullability(DfaPsiUtil.getTypeNullability(componentType)).asDfType());
+ for (int i = 0; i < depth; i++) {
+ if (!(psiType instanceof PsiArrayType arrayType)) return dfType;
+ psiType = arrayType.getComponentType();
}
+ return dfType.meet(DfaNullability.fromNullability(DfaPsiUtil.getTypeNullability(psiType)).asDfType());
}
}
return dfType;
@@ -179,4 +185,18 @@ public final class ArrayElementDescriptor extends JvmVariableDescriptor {
}
return DfaUtil.boxUnbox(factory.fromDfType(dfType), targetType);
}
+
+ /**
+ * @param array array value
+ * @return inherent type of array component
+ */
+ public static @NotNull DfType getArrayComponentType(@NotNull DfaValue array) {
+ DfType componentType = TypeConstraint.fromDfType(array.getDfType()).getArrayComponentType();
+ if (componentType instanceof DfReferenceType &&
+ array instanceof DfaVariableValue var && var.getDescriptor() instanceof PsiVarDescriptor varDescriptor &&
+ varDescriptor.getType(var.getQualifier()) instanceof PsiArrayType arrayType) {
+ return componentType.meet(DfaNullability.fromNullability(DfaPsiUtil.getTypeNullability(arrayType.getComponentType())).asDfType());
+ }
+ return componentType;
+ }
}
diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/NullableArrayComponent.java b/java/java-tests/testData/inspection/dataFlow/fixture/NullableArrayComponent.java
index 36f3af3e6d5d..d7ef4b1c1ae7 100644
--- a/java/java-tests/testData/inspection/dataFlow/fixture/NullableArrayComponent.java
+++ b/java/java-tests/testData/inspection/dataFlow/fixture/NullableArrayComponent.java
@@ -39,4 +39,20 @@ class TestCompilerWarnings {
}
}
+ void multidim(@Nullable String @NotNull[] @NotNull[] a1,
+ @NotNull String @NotNull[] @Nullable[] a2,
+ @NotNull String @Nullable [] @NotNull[] a3) {
+ System.out.println(a1[0][0].length());
+ System.out.println(a2[0][0].length());
+ System.out.println(a3[0][0].length());
+ }
+
+ void multidimParam(@Nullable String @NotNull[] @NotNull[] a1,
+ @NotNull String @NotNull[] @Nullable[] a2,
+ @NotNull String @Nullable [] @NotNull[] a3,
+ int i) {
+ System.out.println(a1[i][i].length()); // Should warn here as well but not supported yet
+ System.out.println(a2[i][i].length());
+ System.out.println(a3[i][i].length());
+ }
}
\ No newline at end of file