diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java index dda92f90bf9e..2fd3cc405bdd 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java @@ -23,13 +23,13 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.util.containers.IntArrayList; import com.intellij.util.containers.Queue; -import com.intellij.util.containers.Stack; -import gnu.trove.THashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; /** * @author max @@ -64,71 +64,67 @@ public class DefUseUtil { } } - private static class InstructionState implements Comparable { - private Set myUsed; - private final InstructionKey myInstructionKey; - private final List myBackwardTraces; + private static class InstructionState { + private Set myVariablesUseArmed; + private final int myInstructionIdx; + private final IntArrayList myBackwardTraces; private boolean myIsVisited; - public InstructionState(@NotNull InstructionKey instructionKey) { - myInstructionKey = instructionKey; - myBackwardTraces = new ArrayList(); - myUsed = null; + public InstructionState(int instructionIdx) { + myInstructionIdx = instructionIdx; + myBackwardTraces = new IntArrayList(); + myVariablesUseArmed = null; } - public void addBackwardTrace(InstructionKey key) { - myBackwardTraces.add(key); + public void addBackwardTrace(int i) { + myBackwardTraces.add(i); } - public List getBackwardTraces() { + public IntArrayList getBackwardTraces() { return myBackwardTraces; } - public InstructionKey getInstructionKey() { - return myInstructionKey; + public int getInstructionIdx() { + return myInstructionIdx; } - void addUsed(PsiVariable psiVariable) { + void mergeUseArmed(PsiVariable psiVariable) { touch(); - myUsed.add(psiVariable); + myVariablesUseArmed.add(psiVariable); } - boolean removeUsed(PsiVariable psiVariable) { + boolean mergeUseDisarmed(PsiVariable psiVariable) { touch(); - return myUsed.remove(psiVariable); + + boolean result = myVariablesUseArmed.contains(psiVariable); + myVariablesUseArmed.remove(psiVariable); + + return result; } private void touch() { - if (myUsed == null) myUsed = new THashSet(); + if (myVariablesUseArmed == null) myVariablesUseArmed = new THashSet(); } - public void addUsedFrom(InstructionState state) { + public void merge(InstructionState state) { touch(); - myUsed.addAll(state.myUsed); + myVariablesUseArmed.addAll(state.myVariablesUseArmed); } public boolean contains(InstructionState state) { - return myUsed != null && state.myUsed != null && - myUsed.containsAll(state.myUsed); + return myVariablesUseArmed != null && state.myVariablesUseArmed != null && + myVariablesUseArmed.containsAll(state.myVariablesUseArmed); } - public void markVisited() { + public boolean markVisited() { + boolean old = myIsVisited; myIsVisited = true; + return old; } public boolean isVisited() { return myIsVisited; } - - @Override - public int compareTo(@NotNull InstructionState other) { - return myInstructionKey.compareTo(other.myInstructionKey); - } - - @Override - public String toString() { - return myInstructionKey + " " + myBackwardTraces + (myIsVisited ? "(v)" : "(n)") + " " + (myUsed != null ? myUsed : "-"); - } } @Nullable @@ -169,11 +165,9 @@ public class DefUseUtil { } } - Map stateMap = getStates(instructions); - InstructionState[] states = stateMap.values().toArray(new InstructionState[0]); - Arrays.sort(states); + InstructionState[] states = getStates(instructions); - BitSet usefulWrites = new BitSet(instructions.size()); + boolean[] defsArmed = new boolean[instructions.size()]; Queue queue = new Queue(8); @@ -184,7 +178,7 @@ public class DefUseUtil { for (PsiVariable psiVariable : assignedVariables) { if (psiVariable instanceof PsiField) { - outerState.addUsed(psiVariable); + outerState.mergeUseArmed(psiVariable); } } queue.addLast(outerState); @@ -194,21 +188,21 @@ public class DefUseUtil { InstructionState state = queue.pullFirst(); state.markVisited(); - InstructionKey key = state.getInstructionKey(); - if (key.getOffset() < instructions.size()) { - Instruction instruction = instructions.get(key.getOffset()); + int idx = state.getInstructionIdx(); + if (idx < instructions.size()) { + Instruction instruction = instructions.get(idx); if (instruction instanceof WriteVariableInstruction) { WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction; PsiVariable psiVariable = writeInstruction.variable; outUsedVariables.add(psiVariable); - if (state.removeUsed(psiVariable)) { - usefulWrites.set(key.getOffset()); + if (state.mergeUseDisarmed(psiVariable)) { + defsArmed[idx] = true; } } else if (instruction instanceof ReadVariableInstruction) { ReadVariableInstruction readInstruction = (ReadVariableInstruction)instruction; - state.addUsed(readInstruction.variable); + state.mergeUseArmed(readInstruction.variable); outUsedVariables.add(readInstruction.variable); } else { @@ -216,11 +210,12 @@ public class DefUseUtil { } } - List backwardTraces = state.getBackwardTraces(); - for (InstructionKey prevKeys : backwardTraces) { - InstructionState prevState = stateMap.get(prevKeys); - if (prevState != null && !prevState.contains(state)) { - prevState.addUsedFrom(state); + IntArrayList backwardTraces = state.getBackwardTraces(); + for (int j = 0; j < backwardTraces.size(); j++) { + int prevIdx = backwardTraces.get(j); + InstructionState prevState = states[prevIdx]; + if (!prevState.contains(state)) { + prevState.merge(state); queue.addLast(prevState); } } @@ -233,7 +228,7 @@ public class DefUseUtil { Instruction instruction = instructions.get(i); if (instruction instanceof WriteVariableInstruction) { WriteVariableInstruction writeInstruction = (WriteVariableInstruction)instruction; - if (!usefulWrites.get(i)) { + if (!defsArmed[i]) { PsiElement context = PsiTreeUtil.getNonStrictParentOfType(flow.getElement(i), PsiStatement.class, PsiAssignmentExpression.class, PsiPostfixExpression.class, PsiPrefixExpression.class); @@ -259,16 +254,16 @@ public class DefUseUtil { public static PsiElement[] getDefs(PsiCodeBlock body, final PsiVariable def, PsiElement ref) { try { RefsDefs refsDefs = new RefsDefs(body) { - private final IntArrayList[] myBackwardTraces = getBackwardTraces(instructions); + private final InstructionState[] states = getStates(instructions); @Override protected int nNext(int index) { - return myBackwardTraces[index].size(); + return states[index].getBackwardTraces().size(); } @Override protected int getNext(int index, int no) { - return myBackwardTraces[index].get(no); + return states[index].getBackwardTraces().get(no); } @Override @@ -412,7 +407,7 @@ public class DefUseUtil { } } - // hack: ControlFlow doesn't contains parameters initialization + // hack: ControlFlow doesnn't contains parameters initialization if (index == 0 && def instanceof PsiParameter) { res.add(def.getNameIdentifier()); } @@ -447,10 +442,10 @@ public class DefUseUtil { } - private static IntArrayList[] getBackwardTraces(final List instructions) { - final IntArrayList[] states = new IntArrayList[instructions.size()]; + private static InstructionState[] getStates(final List instructions) { + final InstructionState[] states = new InstructionState[instructions.size()]; for (int i = 0; i < states.length; i++) { - states[i] = new IntArrayList(); + states[i] = new InstructionState(i); } for (int i = 0; i < instructions.size(); i++) { @@ -458,105 +453,13 @@ public class DefUseUtil { for (int j = 0; j != instruction.nNext(); ++ j) { final int next = instruction.getNext(i, j); if (next < states.length) { - states[next].add(i); + states[next].addBackwardTrace(i); } } } return states; } - private static Map getStates(final List instructions) { - class WalkThroughStack { - private final com.intellij.util.containers.Stack myFrom; - private final com.intellij.util.containers.Stack myNext; - - WalkThroughStack(int size) { - if (size < 2) size = 2; - myFrom = new Stack(size); - myNext = new Stack(size); - } - - void push(InstructionKey fromKey, InstructionKey nextKey) { - myFrom.push(fromKey); - myNext.push(nextKey); - } - - InstructionKey peekFrom() { - return myFrom.peek(); - } - - InstructionKey popNext() { - myFrom.pop(); - return myNext.pop(); - } - - boolean isEmpty() { - return myFrom.isEmpty(); - } - } - - class Walker { - private final Map myStates; - private final WalkThroughStack myWalkThroughStack; - - Walker() { - myStates = new THashMap(instructions.size()); - myWalkThroughStack = new WalkThroughStack(instructions.size() / 2); - } - - Map walk() { - InstructionKey startKey = InstructionKey.create(0); - myStates.put(startKey, new InstructionState(startKey)); - myWalkThroughStack.push(InstructionKey.create(-1), startKey); - - Set visited = new THashSet(instructions.size()); - while (!myWalkThroughStack.isEmpty()) { - InstructionKey fromKey = myWalkThroughStack.peekFrom(); - InstructionKey nextKey = myWalkThroughStack.popNext(); - addBackwardTrace(fromKey, nextKey); - if (!visited.contains(nextKey)) { - visit(nextKey); - visited.add(nextKey); - } - } - return myStates; - } - - private void visit(InstructionKey fromKey) { - if (fromKey.getOffset() >= instructions.size()) return; - final Instruction instruction = instructions.get(fromKey.getOffset()); - if (instruction instanceof CallInstruction) { - int nextOffset = ((CallInstruction)instruction).procBegin; - int returnOffset = fromKey.getOffset() + 1; - InstructionKey nextKey = fromKey.push(nextOffset, returnOffset); - myWalkThroughStack.push(fromKey, nextKey); - } - else if (instruction instanceof ReturnInstruction) { - int overriddenOffset = ((ReturnInstruction)instruction).offset; - InstructionKey nextKey = fromKey.pop(overriddenOffset); - myWalkThroughStack.push(fromKey, nextKey); - } - else { - for (int no = 0; no != instruction.nNext(); no++) { - final int nextOffset = instruction.getNext(fromKey.getOffset(), no); - InstructionKey nextKey = fromKey.next(nextOffset); - myWalkThroughStack.push(fromKey, nextKey); - } - } - } - - private void addBackwardTrace(InstructionKey fromKey, InstructionKey nextKey) { - if (fromKey.getOffset() >= 0 && nextKey.getOffset() < instructions.size()) { - InstructionState state = myStates.get(nextKey); - if (state == null) myStates.put(nextKey, state = new InstructionState(nextKey)); - state.addBackwardTrace(fromKey); - } - } - } - - return new Walker().walk(); - } - private static final ControlFlowPolicy ourPolicy = new ControlFlowPolicy() { @Override public PsiVariable getUsedVariable(@NotNull PsiReferenceExpression refExpr) { diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/InstructionKey.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/InstructionKey.java deleted file mode 100644 index 723ffb52cffc..000000000000 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/InstructionKey.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2000-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.intellij.psi.controlFlow; - -import com.intellij.util.ArrayUtil; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; - -/** - * @author Pavel.Dolgov - */ -class InstructionKey implements Comparable { - private final int myOffset; - private final int[] myCallStack; - - private InstructionKey(int offset, @NotNull int[] callStack) { - myOffset = offset; - myCallStack = callStack; - } - - @NotNull - static InstructionKey create(int offset) { - return new InstructionKey(offset, ArrayUtil.EMPTY_INT_ARRAY); - } - - InstructionKey next(int nextOffset) { - return new InstructionKey(nextOffset, myCallStack); - } - - InstructionKey push(int nextOffset, int returnOffset) { - int[] nextStack = ArrayUtil.append(myCallStack, returnOffset); - return new InstructionKey(nextOffset, nextStack); - } - - InstructionKey pop(int overriddenOffset) { - int returnOffset = myCallStack[myCallStack.length - 1]; - int[] nextStack = ArrayUtil.realloc(myCallStack, myCallStack.length - 1); - int nextOffset = overriddenOffset != 0 ? overriddenOffset : returnOffset; - return new InstructionKey(nextOffset, nextStack); - } - - int getOffset() { - return myOffset; - } - - int[] getCallStack() { - return myCallStack; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - InstructionKey key = (InstructionKey)o; - - if (myOffset != key.myOffset) return false; - if (!Arrays.equals(myCallStack, key.myCallStack)) return false; - - return true; - } - - @Override - public int hashCode() { - int result = myOffset; - result = 31 * result + Arrays.hashCode(myCallStack); - return result; - } - - @Override - public String toString() { - if (myCallStack.length == 0) { - return String.valueOf(myOffset); - } - StringBuilder s = new StringBuilder(); - for (int offset : myCallStack) { - if (s.length() != 0) s.append(','); - s.append(offset); - } - return myOffset + "(" + s + ")"; - } - - @Override - public int compareTo(@NotNull InstructionKey key) { - int c = myOffset - key.myOffset; - if (c != 0) return c; - for (int i = 0, len = Math.min(myCallStack.length, key.myCallStack.length); i < len; i++) { - c = myCallStack[i] - key.myCallStack[i]; - if (c != 0) return c; - } - c = myCallStack.length - key.myCallStack.length; - return c; - } -} diff --git a/java/java-tests/testData/inspection/defUse/IfAfter.java b/java/java-tests/testData/inspection/defUse/IfAfter.java deleted file mode 100644 index 9c970e4b37c5..000000000000 --- a/java/java-tests/testData/inspection/defUse/IfAfter.java +++ /dev/null @@ -1,12 +0,0 @@ -class C { - int f(boolean b) { - int i = 0; - if (b) { - i = 1; - } - else { - i = 2; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/IfBefore.java b/java/java-tests/testData/inspection/defUse/IfBefore.java deleted file mode 100644 index 919d6f70001e..000000000000 --- a/java/java-tests/testData/inspection/defUse/IfBefore.java +++ /dev/null @@ -1,13 +0,0 @@ -class C { - int f(boolean b) { - int i; - if (b) { - i = 1; - } - else { - i = 2; - } - i = 3; - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/IfInLoop.java b/java/java-tests/testData/inspection/defUse/IfInLoop.java deleted file mode 100644 index bffd06abb78e..000000000000 --- a/java/java-tests/testData/inspection/defUse/IfInLoop.java +++ /dev/null @@ -1,10 +0,0 @@ -class C { - int f() { - int i = 0; - for (int j = 0; j < 2; j++) { - if (j == 2) return 1; - i = 1; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/IfNested.java b/java/java-tests/testData/inspection/defUse/IfNested.java deleted file mode 100644 index 0c3a61ef6c94..000000000000 --- a/java/java-tests/testData/inspection/defUse/IfNested.java +++ /dev/null @@ -1,17 +0,0 @@ -class C { - int f(boolean b, boolean c) { - int i = 0; - if (b) { - if (c) { - i = 1; - } - else { - i = 2; - } - } - else { - i = 3; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/InLoop.java b/java/java-tests/testData/inspection/defUse/InLoop.java deleted file mode 100644 index 654f950ef224..000000000000 --- a/java/java-tests/testData/inspection/defUse/InLoop.java +++ /dev/null @@ -1,9 +0,0 @@ -class C { - int f() { - int i = 0; - for (int j = 0; j < 2; j++) { - i = 1; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/NestedBigTryFinally.java b/java/java-tests/testData/inspection/defUse/NestedBigTryFinally.java deleted file mode 100644 index 45dd359a2e03..000000000000 --- a/java/java-tests/testData/inspection/defUse/NestedBigTryFinally.java +++ /dev/null @@ -1,19 +0,0 @@ -class C { - int f() { - int i = 0; - try { - i = 1; - } - finally { - i = 2; - try { - i = 3; - } - finally { - i = 4; - } - i = 5; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/NestedTryFinally.java b/java/java-tests/testData/inspection/defUse/NestedTryFinally.java deleted file mode 100644 index 613e8222aa66..000000000000 --- a/java/java-tests/testData/inspection/defUse/NestedTryFinally.java +++ /dev/null @@ -1,14 +0,0 @@ -class C { - int f() { - int i; - try { - } finally { - i = 1; - try { - i = 2; - } finally { - } - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/Sequence.java b/java/java-tests/testData/inspection/defUse/Sequence.java deleted file mode 100644 index 5c8f3efd9d1c..000000000000 --- a/java/java-tests/testData/inspection/defUse/Sequence.java +++ /dev/null @@ -1,8 +0,0 @@ -class C { - int f() { - int i = 0; - i = 1; - i = 2; - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/ThrowInFinally.java b/java/java-tests/testData/inspection/defUse/ThrowInFinally.java deleted file mode 100644 index db9d87e6695d..000000000000 --- a/java/java-tests/testData/inspection/defUse/ThrowInFinally.java +++ /dev/null @@ -1,12 +0,0 @@ -class C { - int f(boolean b) { - int i; - try { - i = 0; - } finally { - if (b) throw new RuntimeException(); - i = 1; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/ThrowInTry.java b/java/java-tests/testData/inspection/defUse/ThrowInTry.java deleted file mode 100644 index c118d307dd31..000000000000 --- a/java/java-tests/testData/inspection/defUse/ThrowInTry.java +++ /dev/null @@ -1,11 +0,0 @@ -class C { - int f(boolean b) { - int i = 0; - try { - if (b) throw new RuntimeException(); - } finally { - i = 1; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/TryFinally.java b/java/java-tests/testData/inspection/defUse/TryFinally.java deleted file mode 100644 index a8c743d39706..000000000000 --- a/java/java-tests/testData/inspection/defUse/TryFinally.java +++ /dev/null @@ -1,12 +0,0 @@ -class C { - int f(boolean b) { - int i = 0; - try { - i = 1; - } - finally { - i = 2; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/TryThrowFinally.java b/java/java-tests/testData/inspection/defUse/TryThrowFinally.java deleted file mode 100644 index 821bb7363323..000000000000 --- a/java/java-tests/testData/inspection/defUse/TryThrowFinally.java +++ /dev/null @@ -1,13 +0,0 @@ -class C { - int f(boolean b) { - int i = 0; - try { - i = 1; - if (b) throw new RuntimeException(); - } - finally { - i = 2; - } - return i; - } -} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/defUse/TryWithFinallyRethrow.java b/java/java-tests/testData/inspection/defUse/TryWithFinallyRethrow.java deleted file mode 100644 index 15ca531cdbf7..000000000000 --- a/java/java-tests/testData/inspection/defUse/TryWithFinallyRethrow.java +++ /dev/null @@ -1,15 +0,0 @@ -class C { - boolean test(boolean b) { - boolean f = false; - try { - if (b) throw new RuntimeException(); - f = true; - } - catch (RuntimeException e) { - throw e; - } - finally { - } - return f; - } -} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java index 1b552e2e8c31..62ddd52b6d8a 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java @@ -38,22 +38,9 @@ public class DefUseTest extends LightCodeInsightFixtureTestCase { public void testUsedInArrayInitializer() { doTest(); } public void testHang() { doTest(); } public void testOperatorAssignment() { doTest(); } - public void testTryWithFinally() { doTest(); } + @Bombed(user="roman.shevchenko@jetbrains.com", day=1, month=Calendar.AUGUST, year=2017) public void testTryWithFinally() { doTest(); } public void testTryWithoutFinally() { doTest(); } - public void testSequence() { doTest(); } - public void testIfAfter() { doTest(); } - public void testIfBefore() { doTest(); } - public void testIfNested() { doTest(); } - public void testInLoop() { doTest(); } - public void testIfInLoop() { doTest(); } - public void testThrowInTry() { doTest(); } - public void testThrowInFinally() { doTest(); } - public void testTryThrowFinally() { doTest(); } - public void testNestedTryFinally() { doTest(); } - public void testNestedBigTryFinally() { doTest(); } - public void testTryWithFinallyRethrow() { doTest(); } - private void doTest() { myFixture.enableInspections(new DefUseInspection()); myFixture.testHighlighting(getTestName(false) + ".java");