From 90a7c7576d4065a163dcfaf0c47671c031ed0f51 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 5 Dec 2017 10:55:04 +0700 Subject: [PATCH] DFA: improved memory state isSuperState; squash states via isSuperState --- .../dataFlow/DfaInstructionState.java | 9 +++++++++ .../dataFlow/DfaMemoryStateImpl.java | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java index 869bd4f82884..762b22800940 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DfaInstructionState.java @@ -24,6 +24,7 @@ import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; import java.util.*; +import java.util.stream.Collectors; public class DfaInstructionState implements Comparable { public static final DfaInstructionState[] EMPTY_ARRAY = new DfaInstructionState[0]; @@ -93,6 +94,10 @@ class StateQueue { memoryStates.add((DfaMemoryStateImpl)anotherState); } + if (memoryStates.size() > 1) { + memoryStates = squash(memoryStates); + } + if (memoryStates.size() > 1 && joinInstructions.contains(instruction)) { MultiMap groups = MultiMap.create(); for (DfaMemoryStateImpl memoryState : memoryStates) { @@ -109,6 +114,10 @@ class StateQueue { return ContainerUtil.map(memoryStates, state1 -> new DfaInstructionState(instruction, state1)); } + private static List squash(List states) { + return states.stream().filter(left -> states.stream().noneMatch(right -> right != left && right.isSuperStateOf(left))).collect(Collectors.toList()); + } + static List mergeGroup(List group) { if (group.size() < 2) { return group; 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 4debe52014c3..1102b1348b13 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 @@ -382,8 +382,10 @@ public class DfaMemoryStateImpl implements DfaMemoryState { * @return true if current state is a super-state of the supplied state. */ public boolean isSuperStateOf(DfaMemoryStateImpl that) { - if (!equalsSuperficially(that) || - !equalsByUnknownVariables(that) || + if (myEphemeral && !that.myEphemeral) return false; + if (myStack.size() != that.myStack.size()) return false; + if (StreamEx.zip(myStack, that.myStack, DfaMemoryStateImpl::isSuperValue).has(false)) return false; + if (!equalsByUnknownVariables(that) || !that.getDistinctClassPairs().containsAll(getDistinctClassPairs())) { return false; } @@ -410,6 +412,14 @@ public class DfaMemoryStateImpl implements DfaMemoryState { return true; } + private static boolean isSuperValue(DfaValue superValue, DfaValue subValue) { + if (superValue == DfaUnknownValue.getInstance() || superValue == subValue) return true; + if (superValue instanceof DfaFactMapValue && subValue instanceof DfaFactMapValue) { + return ((DfaFactMapValue)superValue).getFacts().isSuperStateOf(((DfaFactMapValue)subValue).getFacts()); + } + return false; + } + private static boolean canBeInRelation(@NotNull DfaValue dfaValue) { DfaValue unwrapped = unwrap(dfaValue); return unwrapped instanceof DfaVariableValue || unwrapped instanceof DfaConstValue;