From 583f188ef66fa7a31d5179b9cfe4e26c3c70392e Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Thu, 12 Jul 2018 13:07:16 +0700 Subject: [PATCH] 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$$$ --- .../dataFlow/ControlFlowAnalyzer.java | 3 ++- .../dataFlow/DfaMemoryStateImpl.java | 4 ++++ .../dataFlow/inliner/StreamChainInliner.java | 3 ++- .../fixture/IncompleteSwitchEnum.java | 20 +++++++++++++++++++ .../DataFlowInspectionTest.java | 1 + 5 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/IncompleteSwitchEnum.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java index a9dc882f6223..e3c0f5f08396 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java @@ -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; } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index 0bc7e0634ddb..cfc328edc497 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -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); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java index ee192f28b6f7..de107041218d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/inliner/StreamChainInliner.java @@ -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 diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/IncompleteSwitchEnum.java b/java/java-tests/testData/inspection/dataFlow/fixture/IncompleteSwitchEnum.java new file mode 100644 index 000000000000..9a7f2e172620 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/IncompleteSwitchEnum.java @@ -0,0 +1,20 @@ +public enum Test { + VALUE; + + void test() { + Integer code = getCode(); + switch (code) { + case VALUE.value() + } + if (code == VALUE.value()) { + getCode(); + } + + } + + int value() { + return ordinal(); + } + + public native Integer getCode(); +} \ No newline at end of file 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 0a9665af2521..614c2b188021 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java @@ -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(); }