From c0409b583d0639e487dacf9d3dfcc3223871ef74 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 14 Mar 2017 17:33:17 +0700 Subject: [PATCH] StateMerger: merge ranges if two states differ only by single variable range (speeds up testLongDisjunctionsNotComplex) --- .../codeInspection/dataFlow/StateMerger.java | 46 +++++++++++++++++++ .../dataFlow/rangeSet/LongRangeSet.java | 18 ++++++++ .../dataFlow/caseAndNpe/src/CaseAndNpe.java | 2 +- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java index 3f80237fee98..b29e539720e2 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StateMerger.java @@ -253,6 +253,52 @@ class StateMerger { return new ArrayList<>(new LinkedHashSet<>(states)); } } + // For every variable with more than one range, try to union range info and see if some states could be merged after that + for (Map.Entry> entry : ranges.entrySet()) { + if (entry.getValue().size() > 1) { + class Record { + final DfaMemoryStateImpl myState; + final LongRangeSet myRange; + + Record(DfaMemoryStateImpl state, LongRangeSet range) { + myState = state; + myRange = range; + } + + Record union(Record other) { + return new Record(myState, myRange.union(other.myRange)); + } + } + + Map merged = new LinkedHashMap<>(); + DfaVariableValue var = entry.getKey(); + for (DfaMemoryStateImpl state : states) { + DfaVariableState variableState = state.getVariableState(var); + LongRangeSet range = variableState.getRange(); + if (range == null) { + range = Objects.requireNonNull(LongRangeSet.fromType(var.getVariableType())); + } + merged.merge(copyWithoutVar(state, var), new Record(state, range), Record::union); + } + if(merged.size() < states.size()) { + List updated = new ArrayList<>(merged.size()); + for (Record record : merged.values()) { + DfaMemoryStateImpl state = record.myState; + DfaVariableState variableState = state.getVariableState(var); + if(!record.myRange.equals(variableState.getRange())) { + state.flushVariable(var); + state.setRange(var, record.myRange); + } + updated.add(state); + } + states = updated; + changed = true; + } + } + } + if (changed) { + return states; + } if (states.size() <= MAX_RANGE_STATES || ranges.isEmpty()) return null; // If there are too many states, try to drop range information from some variable DfaVariableValue lastVar = Collections.max(ranges.keySet(), Comparator.comparingInt(DfaVariableValue::getID)); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java index 19c28e2eab50..ed9ca5fb7d03 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/rangeSet/LongRangeSet.java @@ -79,6 +79,19 @@ public abstract class LongRangeSet { */ public abstract LongRangeSet intersect(LongRangeSet other); + /** + * Merge current set with other + * + * @param other other set to merge with + * @return a new set + */ + public LongRangeSet union(LongRangeSet other) { + if(other.isEmpty() || other == this) return this; + if(other.contains(this)) return other; + // TODO: optimize + return Range.LONG_RANGE.subtract(Range.LONG_RANGE.subtract(this).intersect(Range.LONG_RANGE.subtract(other))); + } + /** * @return a minimal value contained in the set * @throws NoSuchElementException if set is empty @@ -266,6 +279,11 @@ public abstract class LongRangeSet { return this; } + @Override + public LongRangeSet union(LongRangeSet other) { + return other; + } + @Override public long min() { throw new NoSuchElementException(); diff --git a/java/java-tests/testData/inspection/dataFlow/caseAndNpe/src/CaseAndNpe.java b/java/java-tests/testData/inspection/dataFlow/caseAndNpe/src/CaseAndNpe.java index 91643d5815bb..5da75185ed0c 100644 --- a/java/java-tests/testData/inspection/dataFlow/caseAndNpe/src/CaseAndNpe.java +++ b/java/java-tests/testData/inspection/dataFlow/caseAndNpe/src/CaseAndNpe.java @@ -11,7 +11,7 @@ package test.deadcode; import java.io.IOException; public class aaa { - int a; + Object a; int b; void x(int i, Object o) {