From c6f29339aa91af293b180670ccf4bbf67032d5f5 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Mon, 22 Mar 2021 16:53:19 +0700 Subject: [PATCH] [java-dfa] Avoid canonicalizing when flushing from LVA GitOrigin-RevId: f1ba8fc87ede4835e98ed2aceaa792f66a9a529b --- .../codeInspection/dataFlow/DfaMemoryState.java | 13 +++++++++++++ .../codeInspection/dataFlow/DfaMemoryStateImpl.java | 11 ++++++++--- .../dataFlow/NullParameterConstraintChecker.java | 4 ++-- .../instructions/FinishElementInstruction.java | 2 +- .../dataFlow/fixture/StringToCharArray.java | 13 +++++++++++++ 5 files changed, 37 insertions(+), 6 deletions(-) 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();