[java-dfa] Visit catch(AIOOBE) block in case if array access can be successful

GitOrigin-RevId: 49249d1a34b1b29b709bdb76e367ab3c705a05ef
This commit is contained in:
Tagir Valeev
2024-03-15 14:05:59 +00:00
committed by intellij-monorepo-bot
parent 0237abc6f4
commit 4a2a326a25
5 changed files with 50 additions and 7 deletions
@@ -5,8 +5,8 @@ import com.intellij.codeInspection.dataFlow.TypeConstraint;
import com.intellij.codeInspection.dataFlow.interpreter.DataFlowInterpreter;
import com.intellij.codeInspection.dataFlow.java.JavaDfaHelpers;
import com.intellij.codeInspection.dataFlow.jvm.descriptors.ArrayElementDescriptor;
import com.intellij.codeInspection.dataFlow.lang.DfaAnchor;
import com.intellij.codeInspection.dataFlow.jvm.problems.IndexOutOfBoundsProblem;
import com.intellij.codeInspection.dataFlow.lang.DfaAnchor;
import com.intellij.codeInspection.dataFlow.lang.ir.DfaInstructionState;
import com.intellij.codeInspection.dataFlow.lang.ir.ExpressionPushingInstruction;
import com.intellij.codeInspection.dataFlow.lang.ir.Instruction;
@@ -19,6 +19,7 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class ArrayAccessInstruction extends ExpressionPushingInstruction {
@@ -47,6 +48,10 @@ public class ArrayAccessInstruction extends ExpressionPushingInstruction {
public DfaInstructionState[] accept(@NotNull DataFlowInterpreter interpreter, @NotNull DfaMemoryState stateBefore) {
DfaValue index = stateBefore.pop();
DfaValue array = stateBefore.pop();
List<DfaInstructionState> finalStates = new ArrayList<>();
if (myOutOfBoundsTransfer != null) {
finalStates.addAll(IndexOutOfBoundsProblem.dispatchTransfer(interpreter, stateBefore, myOutOfBoundsTransfer));
}
DfaInstructionState[] states = myProblem.processOutOfBounds(interpreter, stateBefore, index, array, myOutOfBoundsTransfer);
if (states != null) return states;
LongRangeSet rangeSet = DfIntType.extractRange(stateBefore.getDfType(index));
@@ -68,7 +73,8 @@ public class ArrayAccessInstruction extends ExpressionPushingInstruction {
}
}
pushResult(interpreter, stateBefore, result);
return nextStates(interpreter, stateBefore);
finalStates.add(nextState(interpreter, stateBefore));
return finalStates.toArray(DfaInstructionState.EMPTY_ARRAY);
}
@Override
@@ -20,6 +20,7 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -53,6 +54,10 @@ public class ArrayStoreInstruction extends ExpressionPushingInstruction {
DfaValue valueToStore = stateBefore.pop();
DfaValue index = stateBefore.pop();
DfaValue array = stateBefore.pop();
List<DfaInstructionState> finalStates = new ArrayList<>();
if (myOutOfBoundsTransfer != null) {
finalStates.addAll(IndexOutOfBoundsProblem.dispatchTransfer(interpreter, stateBefore, myOutOfBoundsTransfer));
}
DfaInstructionState[] states =
myIndexProblem.processOutOfBounds(interpreter, stateBefore, index, array, myOutOfBoundsTransfer);
if (states != null) return states;
@@ -71,7 +76,8 @@ public class ArrayStoreInstruction extends ExpressionPushingInstruction {
stateBefore.flushFieldsQualifiedBy(Set.of(array));
pushResult(interpreter, stateBefore, valueToStore);
}
return nextStates(interpreter, stateBefore);
finalStates.add(nextState(interpreter, stateBefore));
return finalStates.toArray(DfaInstructionState.EMPTY_ARRAY);
}
protected void checkArrayElementAssignability(@NotNull DataFlowInterpreter interpreter,
@@ -45,14 +45,21 @@ public interface IndexOutOfBoundsProblem extends UnsatisfiedConditionProblem {
interpreter.getListener().onCondition(this, index, failed, stateBefore);
if (alwaysOutOfBounds) {
if (outOfBoundsTransfer != null) {
List<DfaInstructionState> states = outOfBoundsTransfer.dispatch(stateBefore, interpreter);
for (DfaInstructionState state : states) {
state.getMemoryState().markEphemeral();
}
List<DfaInstructionState> states = dispatchTransfer(interpreter, stateBefore, outOfBoundsTransfer);
return states.toArray(DfaInstructionState.EMPTY_ARRAY);
}
return DfaInstructionState.EMPTY_ARRAY;
}
return null;
}
static @NotNull List<DfaInstructionState> dispatchTransfer(@NotNull DataFlowInterpreter interpreter,
@NotNull DfaMemoryState stateBefore,
@NotNull DfaControlTransferValue outOfBoundsTransfer) {
List<DfaInstructionState> states = outOfBoundsTransfer.dispatch(stateBefore, interpreter);
for (DfaInstructionState state : states) {
state.getMemoryState().markEphemeral();
}
return states;
}
}
@@ -0,0 +1,22 @@
class Test {
static final int[] DATA = {1, 2, 3};
int test(int value) {
try {
return DATA[value];
}
catch (ArrayIndexOutOfBoundsException e) {
return -1;
}
}
void test2(int value) {
try {
DATA[value] = -1;
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println(e);
}
}
}
@@ -45,6 +45,8 @@ public class UnreachableCodeInspectionTest extends LightJavaCodeInsightFixtureTe
public void testUnresolvedCast() { doTest(); }
public void testUnresolvedCall() { doTest(); }
public void testArrayIndexOutOfBounds() { doTest(); }
private void doTest() {
myFixture.configureByFile(getTestName(false) + ".java");