diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java
index 17ad6210aa28..d8a41876f938 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaMemoryState.java
@@ -144,8 +144,21 @@ public interface DfaMemoryState {
void flushFields();
+ /**
+ * Flush given variable (forget any knowledge about it). Equivalent to {@code flushVariable(variable, true)}
+ * @param variable to flush
+ */
void flushVariable(@NotNull DfaVariableValue variable);
+ /**
+ * Flush given variable (forget any knowledge about it)
+ * @param variable to flush
+ * @param canonicalize whether to canonicalize the variable before flushing. Flushing canonical variable allows to forget
+ * about all known aliases as well. Flushing without canonicalization could be necessary only
+ * to simplify memory state, if it's known that given variable is never used anymore.
+ */
+ void flushVariable(@NotNull DfaVariableValue variable, boolean canonicalize);
+
/**
* Mark this state as ephemeral. See {@link #isEphemeral()} for details.
*/
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 2bc6b6e73a37..de140236b217 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
@@ -1323,11 +1323,16 @@ public class DfaMemoryStateImpl implements DfaMemoryState {
@Override
public void flushVariable(@NotNull DfaVariableValue variable) {
- flushVariable(variable, false);
+ flushVariable(variable, true, false);
}
- protected void flushVariable(@NotNull DfaVariableValue variable, boolean shouldMarkFlushed) {
- DfaVariableValue canonical = canonicalize(variable);
+ @Override
+ public void flushVariable(@NotNull DfaVariableValue variable, boolean canonicalize) {
+ flushVariable(variable, canonicalize, false);
+ }
+
+ protected void flushVariable(@NotNull DfaVariableValue variable, boolean canonicalize, boolean shouldMarkFlushed) {
+ DfaVariableValue canonical = canonicalize ? canonicalize(variable) : variable;
EqClass eqClass = canonical.getDependentVariables().isEmpty() ? null : getEqClass(canonical);
DfaVariableValue newCanonical =
eqClass == null ? null : StreamEx.of(eqClass.iterator()).without(canonical).min(EqClass.CANONICAL_VARIABLE_COMPARATOR)
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java
index e5b0578406a2..f36070b7306a 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/NullParameterConstraintChecker.java
@@ -131,10 +131,10 @@ final class NullParameterConstraintChecker extends DataFlowRunner {
}
@Override
- protected void flushVariable(@NotNull DfaVariableValue variable, boolean shouldMarkFlushed) {
+ protected void flushVariable(@NotNull DfaVariableValue variable, boolean canonicalize, boolean shouldMarkFlushed) {
final PsiModifierListOwner psi = variable.getPsiVariable();
if (psi instanceof PsiParameter && myPossiblyViolatedParameters.contains(psi)) return;
- super.flushVariable(variable, shouldMarkFlushed);
+ super.flushVariable(variable, canonicalize, shouldMarkFlushed);
}
@NotNull
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FinishElementInstruction.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FinishElementInstruction.java
index fc6e9734cf1b..5ccf96f2ba44 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FinishElementInstruction.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/instructions/FinishElementInstruction.java
@@ -26,7 +26,7 @@ public class FinishElementInstruction extends Instruction {
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState state, InstructionVisitor visitor) {
if (!myVarsToFlush.isEmpty()) {
for (DfaVariableValue value : myVarsToFlush) {
- state.flushVariable(value);
+ state.flushVariable(value, false);
}
}
return nextInstruction(runner, state);
diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/StringToCharArray.java b/java/java-tests/testData/inspection/dataFlow/fixture/StringToCharArray.java
index 655513d06c59..15114939c120 100644
--- a/java/java-tests/testData/inspection/dataFlow/fixture/StringToCharArray.java
+++ b/java/java-tests/testData/inspection/dataFlow/fixture/StringToCharArray.java
@@ -5,6 +5,19 @@ import java.util.Set;
import org.jetbrains.annotations.Contract;
public class StringToCharArray {
+ final String field;
+ final int[] bogus = new int[128];
+
+ StringToCharArray(String s) {
+ if (s.isEmpty()) throw new IllegalArgumentException();
+ field = s;
+ char[] chars = field.toCharArray();
+ if (chars.length != field.length()) {}
+ if (s.isEmpty()) {
+
+ }
+ }
+
void test(String s) {
if (s.startsWith("--")) {
char[] arr = s.toCharArray();