ControlFlowAnalyzer: repeat unboxing for every case label if necessary

Without this it was possible (at least on the incorrect code) that boxed and unboxed classes for the same value get united, which in turn caused repeating entry in DfaMemoryStateImpl#myIdToEqClassesIndices, which could cause NPE when performing successive flush for given variable.
Now we throw directly at classes unification attempt to catch illegal state earlier
Fixes EA-118152 - IAE: EqClass.$$$reportNull$$$
This commit is contained in:
Tagir Valeev
2018-07-12 13:07:16 +07:00
parent 7730b97ee4
commit 583f188ef6
5 changed files with 29 additions and 2 deletions
@@ -899,6 +899,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
((PsiReferenceExpression)caseExpression).getQualifierExpression() == null) {
addInstruction(new PushInstruction(myFactory.createValue(caseExpression), caseExpression));
generateBoxingUnboxingInstructionFor(caseExpression, PsiType.INT);
caseValue.accept(this);
addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, PsiType.BOOLEAN));
}
@@ -2066,7 +2067,7 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
private static final class Synthetic implements DfaVariableSource {
private final int myLocation;
public Synthetic(int location) {
private Synthetic(int location) {
myLocation = location;
}
@@ -344,6 +344,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
classes = new int[]{index};
}
else {
if (ArrayUtil.indexOf(classes, index) != -1) {
throw new IllegalStateException("Class index already referenced from the value: "+
myEqClasses.get(index)+"; "+myFactory.getValue(id));
}
classes = ArrayUtil.append(classes, index);
}
myIdToEqClassesIndices.put(id, classes);
@@ -246,7 +246,8 @@ public class StreamChainInliner implements CallInliner {
if (!(type instanceof PsiPrimitiveType)) {
type = PsiPrimitiveType.getUnboxedType(type);
}
builder.push(builder.getFactory().getConstFactory().createDefault(Objects.requireNonNull(type)));
builder.push(builder.getFactory().getConstFactory().createDefault(Objects.requireNonNull(type)))
.boxUnbox(myCall, type, myCall.getType());
}
@Override
@@ -0,0 +1,20 @@
public enum Test {
VALUE;
void test() {
Integer code = getCode();
switch (code) {
case VALUE.value()<EOLError descr="':' expected"></EOLError>
}
if (code == VALUE.value()) {
getCode();
}
}
int value() {
return ordinal();
}
public native Integer getCode();
}
@@ -96,6 +96,7 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
public void testNotEqualsDoesntImplyNotNullity() { doTest(); }
public void testEqualsEnumConstant() { doTest(); }
public void testSwitchEnumConstant() { doTest(); }
public void testIncompleteSwitchEnum() { doTest(); }
public void testEnumConstantNotNull() { doTest(); }
public void testCheckEnumConstantConstructor() { doTest(); }
public void testCompareToEnumConstant() { doTest(); }