diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java index f980f68f8f2a..b6cff314da67 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java @@ -60,4 +60,6 @@ public interface DfaMemoryState { boolean isNotNull(DfaVariableValue dfaVar); void flushVariableOutOfScope(DfaVariableValue variable); + + void fieldReferenced(); } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java index e291c92f2bcd..7763c26eaf1c 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryStateImpl.java @@ -51,7 +51,8 @@ public class DfaMemoryStateImpl implements DfaMemoryState { private Stack myStack; private TIntStack myOffsetStack; private TLongHashSet myDistinctClasses; - private Map myVariableStates; + private THashMap myVariableStates; + private boolean myHasDirtyFields = true; public DfaMemoryStateImpl(final DfaValueFactory factory) { myFactory = factory; @@ -80,6 +81,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { newState.myStateSize = myStateSize; newState.myVariableStates = new THashMap(); newState.myOffsetStack = new TIntStack(myOffsetStack); + newState.myHasDirtyFields = myHasDirtyFields; for (int i = 0; i < myEqClasses.size(); i++) { SortedIntSet aClass = myEqClasses.get(i); @@ -110,6 +112,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { if (!myStack.equals(that.myStack)) return false; if (!myOffsetStack.equals(that.myOffsetStack)) return false; if (!myVariableStates.equals(that.myVariableStates)) return false; + if (myHasDirtyFields != that.myHasDirtyFields) return false; int[] permutation = getPermutationToSortedState(); int[] thatPermutation = that.getPermutationToSortedState(); @@ -461,6 +464,11 @@ public class DfaMemoryStateImpl implements DfaMemoryState { myDistinctClasses.add(createPair(c1Index, c2Index)); } + @Override + public void fieldReferenced() { + myHasDirtyFields = true; + } + public boolean isNull(DfaValue dfaValue) { if (dfaValue instanceof DfaNotNullValue) return false; @@ -674,6 +682,9 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } public void flushFields(DataFlowRunner runner) { + if (!myHasDirtyFields) return; + + myHasDirtyFields = false; DfaVariableValue[] fields = runner.getFields(); for (DfaVariableValue field : fields) { boolean resetNullability = isNotNull(field); @@ -690,17 +701,19 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } doFlash(variable); - doFlash((DfaVariableValue)variable.createNegated()); } @Override public void flushVariableOutOfScope(DfaVariableValue variable) { doFlash(variable); - doFlash((DfaVariableValue)variable.createNegated()); } - private void doFlash(DfaVariableValue variable) { - final int id = variable.getID(); + private void doFlash(DfaVariableValue varPlain) { + DfaVariableValue varNegated = (DfaVariableValue)varPlain.createNegated(); + + final int idPlain = varPlain.getID(); + final int idNegated = varNegated.getID(); + int size = myEqClasses.size(); int interruptCount = 0; for (int varClassIndex = 0; varClassIndex < size; varClassIndex++) { @@ -713,9 +726,7 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } int cl = varClass.get(i); DfaValue value = myFactory.getValue(cl); - if (value != null && id == value.getID() || - value instanceof DfaBoxedValue && ((DfaBoxedValue)value).getWrappedValue().getID() == id || - value instanceof DfaUnboxedValue && ((DfaUnboxedValue)value).getVariable().getID() == id) { + if (mine(idPlain, value) || mine(idNegated, value)) { varClass.remove(i); break; } @@ -733,6 +744,13 @@ public class DfaMemoryStateImpl implements DfaMemoryState { } } - myVariableStates.remove(variable); + myVariableStates.remove(varPlain); + myVariableStates.remove(varNegated); + } + + private static boolean mine(int id, DfaValue value) { + return value != null && id == value.getID() || + value instanceof DfaBoxedValue && ((DfaBoxedValue)value).getWrappedValue().getID() == id || + value instanceof DfaUnboxedValue && ((DfaUnboxedValue)value).getVariable().getID() == id; } } diff --git a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java index 218c68c27659..5ce2fbd6c1f5 100644 --- a/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java +++ b/java/java-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java @@ -119,6 +119,7 @@ public class StandardInstructionVisitor extends InstructionVisitor { @Override public DfaInstructionState[] visitFieldReference(FieldReferenceInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) { + memState.fieldReferenced(); final DfaValue qualifier = memState.pop(); if (instruction.getExpression().isPhysical() && !memState.applyNotNull(qualifier)) { onInstructionProducesNPE(instruction, runner);