diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java index d68bf8143b9c..4f9627352366 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java @@ -99,13 +99,13 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { result = new IntIdFinal(((Final)rhs).value); } else { Pending pending = (Pending)rhs; - Set> deltaOrig = pending.delta; - IntIdComponent[] components = new IntIdComponent[deltaOrig.size()]; + Set> sumOrigin = pending.sum; + IntIdComponent[] components = new IntIdComponent[sumOrigin.size()]; int componentI = 0; - for (Set keyComponent : deltaOrig) { - int[] ids = new int[keyComponent.size()]; + for (Product prod : sumOrigin) { + int[] ids = new int[prod.ids.size()]; int idI = 0; - for (Key id : keyComponent) { + for (Key id : prod.ids) { int[] compoundKey = mkCompoundKey(id); int rawId = myCompoundKeyEnumerator.enumerate(compoundKey); if (rawId <= 0) { @@ -114,11 +114,11 @@ public class BytecodeAnalysisConverter implements ApplicationComponent { ids[idI] = id.stable ? rawId : -rawId; idI++; } - IntIdComponent intIdComponent = new IntIdComponent(ids); + IntIdComponent intIdComponent = new IntIdComponent(prod.value, ids); components[componentI] = intIdComponent; componentI++; } - result = new IntIdPending(pending.infinum, pending.rigid, components); + result = new IntIdPending(components); } int rawKey = myCompoundKeyEnumerator.enumerate(mkCompoundKey(equation.id)); diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java index 7af5b0e3fa7c..a4f66375bf6e 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java @@ -91,19 +91,17 @@ public class BytecodeAnalysisIndex extends FileBasedIndexExtension> { private final InOutInterpreter interpreter; private final Value inValue; - private boolean nullAnalysis; protected InOutAnalysis(RichControlFlow richControlFlow, Direction direction, TIntHashSet resultOrigins, boolean stable) { super(richControlFlow, direction, stable); interpreter = new InOutInterpreter(direction, richControlFlow.controlFlow.methodNode.instructions, resultOrigins); inValue = direction instanceof InOut ? ((InOut)direction).inValue : null; - nullAnalysis = (direction instanceof InOut) && (((InOut)direction).inValue) == Value.Null; } @Override @@ -65,8 +63,10 @@ class InOutAnalysis extends Analysis> { @Override boolean isEarlyResult(Result res) { - Value value = res instanceof Final ? ((Final)res).value : ((Pending)res).infinum; - return value == Value.Top; + if (res instanceof Final) { + return ((Final)res).value == Value.Top; + } + return false; } @Override @@ -126,9 +126,7 @@ class InOutAnalysis extends Analysis> { } else if (stackTop instanceof CallResultValue) { Set keys = ((CallResultValue) stackTop).inters; - Set> components = new HashSet>(); - components.add(keys); - results.put(stateIndex, new Pending(Value.Bot, false, components)); + results.put(stateIndex, new Pending(Collections.singleton(new Product(Value.Top, keys)))); computed.put(insnIndex, append(computed.get(insnIndex), state)); } else { diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java index c2f989efa6fb..1ff0c19697b9 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java @@ -153,11 +153,11 @@ class NonNullInAnalysis extends Analysis { } else { ConditionalNPE condNpe = (ConditionalNPE) result; - Set> components = new HashSet>(); + Set> components = new HashSet>(); for (Set prod : condNpe.sop) { - components.add(prod); + components.add(new Product(Value.Top, prod)); } - return new Equation(aKey, new Pending(Value.NotNull, false, components)); + return new Equation(aKey, new Pending(components)); } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java index 8866ad732915..61193734e37d 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java @@ -17,10 +17,10 @@ package com.intellij.codeInspection.bytecodeAnalysis; import com.intellij.util.containers.IntStack; import com.intellij.util.containers.IntToIntSetMap; +import com.sun.istack.internal.NotNull; import gnu.trove.TIntObjectHashMap; import java.util.*; -import static com.intellij.codeInspection.bytecodeAnalysis.IdUtils.*; final class ELattice> { final T bot; @@ -48,81 +48,60 @@ final class ELattice> { // component specialized for ints final class IntIdComponent { + Value value; final int[] ids; + IntIdComponent(Value value, int[] ids) { + this.value = value; + this.ids = ids; + } + @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof IntIdComponent)) return false; + if (o == null || getClass() != o.getClass()) return false; - IntIdComponent component = (IntIdComponent)o; + IntIdComponent that = (IntIdComponent)o; - if (!Arrays.equals(ids, component.ids)) return false; + if (!Arrays.equals(ids, that.ids)) return false; + if (value != that.value) return false; return true; } @Override public int hashCode() { - return Arrays.hashCode(ids); + return value.ordinal() + Arrays.hashCode(ids); } - IntIdComponent(int[] ids) { - this.ids = ids; - } - - public void remove(int id) { - IdUtils.remove(ids, id); - } - - public boolean isEmptyAndTouched() { - return IdUtils.isEmptyAndTouched(ids); + public boolean remove(int id) { + return IdUtils.remove(ids, id); } public boolean isEmpty() { return IdUtils.isEmpty(ids); } - - public void removeAndTouch(int id) { - IdUtils.removeAndTouch(ids, id); - } } class IdUtils { - // absent value - static final int nullId = -1; - static final int touchedId = -2; + // removed value + static final int nullId = 0; static boolean contains(int[] ids, int id) { - for (int i : ids) { - if (i == id) { - return true; - } + for (int id1 : ids) { + if (id1 == id) return true; } + return false; } static boolean isEmpty(int[] ids) { - for (int i : ids) { - if (i != nullId && i != touchedId) { - return false; - } + for (int id : ids) { + if (id != nullId) return false; } return true; } - - static boolean isEmptyAndTouched(int[] ids) { - boolean touched = false; - for (int i : ids) { - if (i != nullId && i != touchedId) { - return false; - } - touched = touched || i == touchedId; - } - return touched; - } - static IntIdComponent[] toArray(Collection set) { IntIdComponent[] result = new IntIdComponent[set.size()]; int i = 0; @@ -130,23 +109,19 @@ class IdUtils { result[i] = intIdComponent; i++; } + return result; } - static void remove(int[] ids, int id) { + static boolean remove(int[] ids, int id) { + boolean removed = false; for (int i = 0; i < ids.length; i++) { if (ids[i] == id) { ids[i] = nullId; + removed = true; } } - } - - static void removeAndTouch(int[] ids, int id) { - for (int i = 0; i < ids.length; i++) { - if (ids[i] == id) { - ids[i] = touchedId; - } - } + return removed; } } @@ -169,19 +144,55 @@ class ResultUtil> { return new Final(lattice.join(((Final) r1).value, ((Final) r2).value)); } if (r1 instanceof Final && r2 instanceof Pending) { + Final f1 = (Final)r1; Pending pending = (Pending) r2; - return new Pending(lattice.join(((Final) r1).value, pending.infinum), true, pending.delta); + Set> sum1 = new HashSet>(pending.sum); + sum1.add(new Product(f1.value, Collections.emptySet())); + return new Pending(sum1); } if (r1 instanceof Pending && r2 instanceof Final) { + Final f2 = (Final)r2; Pending pending = (Pending) r1; - return new Pending(lattice.join(((Final) r2).value, pending.infinum), true, pending.delta); + Set> sum1 = new HashSet>(pending.sum); + sum1.add(new Product(f2.value, Collections.emptySet())); + return new Pending(sum1); } Pending pending1 = (Pending) r1; Pending pending2 = (Pending) r2; - Set> delta = new HashSet>(); - delta.addAll(pending1.delta); - delta.addAll(pending2.delta); - return new Pending(lattice.join(pending1.infinum, pending2.infinum), pending1.rigid || pending2.rigid, delta); + Set> sum = new HashSet>(); + sum.addAll(pending1.sum); + sum.addAll(pending2.sum); + return new Pending(sum); + } +} + +final class Product { + @NotNull final V value; + @NotNull final Set ids; + + Product(@NotNull V value, @NotNull Set ids) { + this.value = value; + this.ids = ids; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Product product = (Product)o; + + if (!ids.equals(product.ids)) return false; + if (!value.equals(product.value)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = value.hashCode(); + result = 31 * result + ids.hashCode(); + return result; } } @@ -199,20 +210,12 @@ final class Final implements Result { } final class Pending implements Result { - final T infinum; - final boolean rigid; - final Set> delta; + final Set> sum; - Pending(T infinum, boolean rigid, Set> delta) { - this.infinum = infinum; - this.rigid = rigid; - this.delta = delta; + Pending(Set> sum) { + this.sum = sum; } - @Override - public String toString() { - return "Pending{" + "infinum=" + infinum + ", rigid=" + rigid + ", delta=" + delta + '}'; - } } interface IntIdResult {} @@ -223,14 +226,11 @@ final class IntIdFinal implements IntIdResult { this.value = value; } } + final class IntIdPending implements IntIdResult { - final Value infinum; - final boolean rigid; final IntIdComponent[] delta; - IntIdPending(Value infinum, boolean rigid, IntIdComponent[] delta) { - this.infinum = infinum; - this.rigid = rigid; + IntIdPending(IntIdComponent[] delta) { this.delta = delta; } @@ -238,22 +238,13 @@ final class IntIdPending implements IntIdResult { public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof IntIdPending)) return false; - IntIdPending pending = (IntIdPending)o; - - if (!Arrays.equals(delta, pending.delta)) return false; - if (rigid != pending.rigid) return false; - if (infinum != pending.infinum) return false; - - return true; + return !Arrays.equals(delta, pending.delta); } @Override public int hashCode() { - int result = infinum.ordinal(); - result = 31 * result + (rigid ? 1 : 0); - result = 31 * result + Arrays.hashCode(delta); - return result; + return Arrays.hashCode(delta); } } @@ -331,14 +322,9 @@ final class IntIdSolver { moving.push(equation.id); } else if (rhs instanceof IntIdPending) { IntIdPending pendResult = (IntIdPending)rhs; - if (pendResult.infinum == lattice.top) { - solved.put(equation.id, lattice.top); - moving.push(equation.id); - } else { - for (IntIdComponent component : pendResult.delta) { - for (int trigger : component.ids) { - dependencies.addOccurence(trigger, equation.id); - } + for (IntIdComponent component : pendResult.delta) { + for (int trigger : component.ids) { + dependencies.addOccurence(trigger, equation.id); } pending.put(equation.id, pendResult); } @@ -381,67 +367,24 @@ final class IntIdSolver { // substitute id -> value into pending IntIdResult substitute(IntIdPending pending, int id, Value value) { - if (value == lattice.bot) { - // remove components (products) with bottom - ArrayList delta = new ArrayList(); - for (IntIdComponent component : pending.delta) { - if (!contains(component.ids, id)) { - delta.add(component); - } - } - if (delta.isEmpty()) { - return pending.rigid ? new IntIdFinal(pending.infinum) : new IntIdFinal(lattice.bot); - } - else { - return new IntIdPending(pending.infinum, pending.rigid, toArray(delta)); + for (IntIdComponent intIdComponent : pending.delta) { + if (intIdComponent.remove(id)) { + intIdComponent.value = lattice.meet(intIdComponent.value, value); } } - else if (value.equals(lattice.top)) { - ArrayList delta = new ArrayList(); - // remove top from components - boolean removed = false; - for (IntIdComponent component : pending.delta) { - component.remove(id); - if (!component.isEmptyAndTouched()) { - if (component.isEmpty()) { - return new IntIdFinal(lattice.top); - } else { - delta.add(component); - } - } - else { - removed = true; - } - } - if (delta.isEmpty()) { - return new IntIdFinal(pending.infinum); - } - else { - return new IntIdPending(pending.infinum, pending.rigid || removed, toArray(delta)); - } - } - else { - Value infinum = lattice.join(pending.infinum, value); - if (infinum == lattice.top) { + // normalized? + Value acc = lattice.bot; + for (IntIdComponent intIdComponent : pending.delta) { + if (intIdComponent.value == lattice.top && intIdComponent.isEmpty()) { return new IntIdFinal(lattice.top); } - ArrayList delta = new ArrayList(); - boolean removed = false; - for (IntIdComponent component : pending.delta) { - component.removeAndTouch(id); - if (!component.isEmpty()) { - delta.add(component); - } - else { - removed = true; - } - } - if (delta.isEmpty()) { - return new IntIdFinal(infinum); - } - else { - return new IntIdPending(infinum, pending.rigid || removed, toArray(delta)); + else if (intIdComponent.value != lattice.bot) { + if (intIdComponent.isEmpty()) + acc = lattice.join(acc, intIdComponent.value); + else + return pending; } } + return new IntIdFinal(acc); } }