From d03fcb1710e290959b97fe4584df9cddf589e2ec Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Fri, 3 Sep 2010 19:32:56 +0400 Subject: [PATCH] never ending def use --- .../intellij/psi/controlFlow/DefUseUtil.java | 76 ++++++------ .../inspection/defUse/Hang/expected.xml | 4 + .../inspection/defUse/Hang/src/Foo.java | 109 +++++++++++++++++ .../intellij/codeInspection/DefUseTest.java | 19 +-- .../com/intellij/util/containers/Queue.java | 115 ++++++------------ 5 files changed, 198 insertions(+), 125 deletions(-) create mode 100644 java/java-tests/testData/inspection/defUse/Hang/expected.xml create mode 100644 java/java-tests/testData/inspection/defUse/Hang/src/Foo.java diff --git a/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java b/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java index 687de99e9b24..fb05c91b2d72 100644 --- a/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java +++ b/java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java @@ -30,6 +30,7 @@ import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.IntArrayList; +import com.intellij.util.containers.Queue; import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; @@ -105,25 +106,24 @@ public class DefUseUtil { return result; } - void touch() { + private void touch() { if (myVariablesUseArmed == null) myVariablesUseArmed = new THashSet(); } - public boolean equals(Object obj) { - InstructionState state = (InstructionState) obj; - if (myVariablesUseArmed == null && state.myVariablesUseArmed == null) return true; - if (myVariablesUseArmed == null || state.myVariablesUseArmed == null) return false; - - return myVariablesUseArmed.equals(state.myVariablesUseArmed); - } - public void merge(InstructionState state) { touch(); myVariablesUseArmed.addAll(state.myVariablesUseArmed); } - public void markVisited() { + public boolean contains(InstructionState state) { + return myVariablesUseArmed != null && state.myVariablesUseArmed != null && + myVariablesUseArmed.containsAll(state.myVariablesUseArmed); + } + + public boolean markVisited() { + boolean old = myIsVisited; myIsVisited = true; + return old; } public boolean isVisited() { @@ -172,9 +172,8 @@ public class DefUseUtil { InstructionState[] states = getStates(instructions); boolean[] defsArmed = new boolean[instructions.size()]; - for (int i = 0; i < defsArmed.length; i++) defsArmed[i] = false; - List queue = new ArrayList(); + Queue queue = new Queue(8); for (int i = states.length - 1; i >= 0; i--) { final InstructionState outerState = states[i]; @@ -186,11 +185,11 @@ public class DefUseUtil { outerState.mergeUseArmed(psiVariable); } } - queue.add(outerState); + queue.addLast(outerState); while (!queue.isEmpty()) { ProgressManager.checkCanceled(); - InstructionState state = queue.remove(0); + InstructionState state = queue.pullFirst(); state.markVisited(); int idx = state.getInstructionIdx(); @@ -215,11 +214,13 @@ public class DefUseUtil { } } - for (int j = 0; j < state.getBackwardTraces().size(); j++) { - int prevIdx = state.getBackwardTraces().get(j); - if (!state.equals(states[prevIdx])) { - states[prevIdx].merge(state); - queue.add(states[prevIdx]); + 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); } } } @@ -255,9 +256,8 @@ public class DefUseUtil { @NotNull public static PsiElement[] getDefs(PsiCodeBlock body, final PsiVariable def, PsiElement ref) { try { - return new RefsDefs(body) { - - final InstructionState[] states = getStates(instructions); + RefsDefs refsDefs = new RefsDefs(body) { + private final InstructionState[] states = getStates(instructions); protected int nNext(int index) { return states[index].getBackwardTraces().size(); @@ -267,7 +267,9 @@ public class DefUseUtil { return states[index].getBackwardTraces().get(no); } - protected boolean defs() { return true; } + protected boolean defs() { + return true; + } protected void processInstruction(final Set res, final Instruction instruction, int index) { if (instruction instanceof WriteVariableInstruction) { @@ -276,14 +278,17 @@ public class DefUseUtil { final PsiElement element = flow.getElement(index); element.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceExpression(PsiReferenceExpression ref) { + @Override + public void visitReferenceExpression(PsiReferenceExpression ref) { if (PsiUtil.isAccessedForWriting(ref)) { if (ref.resolve() == def) { res.add(ref); } } } - @Override public void visitVariable(PsiVariable var) { + + @Override + public void visitVariable(PsiVariable var) { if (var == def && (var instanceof PsiParameter || var.hasInitializer())) { res.add(var); } @@ -292,7 +297,8 @@ public class DefUseUtil { } } } - }.get(def, ref); + }; + return refsDefs.get(def, ref); } catch (AnalysisCanceledException e) { return PsiElement.EMPTY_ARRAY; @@ -302,8 +308,7 @@ public class DefUseUtil { @NotNull public static PsiElement[] getRefs(PsiCodeBlock body, final PsiVariable def, PsiElement ref) { try { - return new RefsDefs(body) { - + RefsDefs refsDefs = new RefsDefs(body) { protected int nNext(int index) { return instructions.get(index).nNext(); } @@ -312,7 +317,9 @@ public class DefUseUtil { return instructions.get(index).getNext(index, no); } - protected boolean defs() { return false; } + protected boolean defs() { + return false; + } protected void processInstruction(final Set res, final Instruction instruction, int index) { if (instruction instanceof ReadVariableInstruction) { @@ -321,7 +328,8 @@ public class DefUseUtil { final PsiElement element = flow.getElement(index); element.accept(new JavaRecursiveElementWalkingVisitor() { - @Override public void visitReferenceExpression(PsiReferenceExpression ref) { + @Override + public void visitReferenceExpression(PsiReferenceExpression ref) { if (ref.resolve() == def) { res.add(ref); } @@ -330,15 +338,15 @@ public class DefUseUtil { } } } - }.get(def, ref); + }; + return refsDefs.get(def, ref); } catch (AnalysisCanceledException e) { return PsiElement.EMPTY_ARRAY; } } - protected abstract static class RefsDefs { - + private abstract static class RefsDefs { protected abstract int nNext(int index); protected abstract int getNext(int index, int no); @@ -357,7 +365,7 @@ public class DefUseUtil { protected abstract boolean defs (); @NotNull - PsiElement[] get (final PsiVariable def, PsiElement refOrDef) { + private PsiElement[] get (final PsiVariable def, PsiElement refOrDef) { if (body == null) { return PsiElement.EMPTY_ARRAY; } diff --git a/java/java-tests/testData/inspection/defUse/Hang/expected.xml b/java/java-tests/testData/inspection/defUse/Hang/expected.xml new file mode 100644 index 000000000000..d704d58ed391 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/Hang/expected.xml @@ -0,0 +1,4 @@ + + + + diff --git a/java/java-tests/testData/inspection/defUse/Hang/src/Foo.java b/java/java-tests/testData/inspection/defUse/Hang/src/Foo.java new file mode 100644 index 000000000000..06b20f833930 --- /dev/null +++ b/java/java-tests/testData/inspection/defUse/Hang/src/Foo.java @@ -0,0 +1,109 @@ +public class DefUse { + + private int deflate_fast(int flush, int lookahead, int match_length) { + // short hash_head = 0; // head of the hash chain + int hash_head = 0; // head of the hash chain + boolean bflush; // set if current block must be flushed + + while (true) { + // Make sure that we always have enough lookahead, except + // at the end of the input file. We need MAX_MATCH bytes + // for the next match, plus MIN_MATCH bytes to insert the + // string following the next match. + if (lookahead < 1) { + if (lookahead < 1 && flush == JZlib.Z_NO_FLUSH) { + return 0; + } + if (lookahead == 0) { + break; // flush the current block + } + } + + // Insert the string window[strstart .. strstart+2] in the + // dictionary, and set hash_head to the head of the hash chain: + if (lookahead >= 0) { + ins_h = (ins_h << hash_shift ^ window[strstart + 0 - 1] & 0xff) & + hash_mask; + + // prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = 0xffff; + } + + // Find the longest match, discarding those <= prev_length. + // At this point we have always match_length < MIN_MATCH + + if (hash_head != 0L && + (strstart - hash_head & 0xffff) <= w_size - 1) { + // To simplify the code, we prevent matches with the string + // of window index 0 (in particular we have to avoid a match + // of the string with itself at the start of the input file). + if (strategy != JZlib.Z_HUFFMAN_ONLY) { + match_length = longest_match(hash_head); + } + // longest_match() sets match_start + } + if (match_length >= 0) { + // check_match(strstart, match_start, match_length); + + bflush = _tr_tally(strstart - match_start, match_length - + 0); + + lookahead -= match_length; + + // Insert new strings in the hash table only if the match length + // is not too large. This saves time but degrades compression. + if (match_length <= max_lazy_match && lookahead >= 0) { + match_length --; // string at strstart already in hash table + do { + strstart ++; + + ins_h = (ins_h << hash_shift ^ window[strstart + + 0 - 1] & 0xff) & + hash_mask; + // prev[strstart&w_mask]=hash_head=head[ins_h]; + hash_head = head[ins_h] & 0xffff; + prev[strstart & w_mask] = head[ins_h]; + head[ins_h] = (short) strstart; + + // strstart never exceeds WSIZE-MAX_MATCH, so there are + // always MIN_MATCH bytes ahead. + } while (-- match_length != 0); + strstart ++; + } else { + strstart += match_length; + match_length = 0; + ins_h = window[strstart] & 0xff; + + ins_h = (ins_h << hash_shift ^ window[strstart + 1] & 0xff) & + hash_mask; + // If lookahead < MIN_MATCH, ins_h is garbage, but it does not + // matter since it will be recomputed at next deflate call. + } + } else { + // No match, output a literal byte + + bflush = _tr_tally(0, window[strstart] & 0xff); + lookahead --; + strstart ++; + } + if (bflush) { + + flush_block_only(false); + if (strm.avail_out == 0) { + return 0; + } + } + } + + flush_block_only(flush == JZlib.Z_FINISH); + if (flush == 0) { + if (flush == JZlib.Z_FINISH) { + return 1; + } else { + return 0; + } + } + return flush == JZlib.Z_FINISH? 1 : 0; + } + +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java index 1c7c240ec32b..9dd090b05909 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java @@ -30,21 +30,14 @@ public class DefUseTest extends InspectionTestCase { public void testarrayIndexUsages() throws Exception { doTest(); } - /* TODO: + + // TODO: public void testSCR28019() throws Exception { doTest(); } - */ - public void testSCR40364() throws Exception { - doTest(); - } - - public void testArrayLength() throws Exception { - doTest(); - } - - public void testUsedInArrayInitializer() throws Exception { - doTest(); - } + public void testSCR40364() throws Exception { doTest(); } + public void testArrayLength() throws Exception { doTest(); } + public void testUsedInArrayInitializer() throws Exception { doTest(); } + public void testHang() throws Exception { doTest(); } } diff --git a/platform/util/src/com/intellij/util/containers/Queue.java b/platform/util/src/com/intellij/util/containers/Queue.java index 689d851616bc..79da1445dda4 100644 --- a/platform/util/src/com/intellij/util/containers/Queue.java +++ b/platform/util/src/com/intellij/util/containers/Queue.java @@ -19,31 +19,29 @@ import java.util.Arrays; import java.util.List; public class Queue { - private final NormalState NORMAL_STATE = new NormalState(); - private final InvertedState INVERTED_STATE = new InvertedState(); - private Object[] myArray; - private int myFirst = 0; - private int myLast = 0; - private QueueState myState = NORMAL_STATE; + private int myFirst; + private int myLast; + private boolean isInverted; public Queue(int initialCapacity) { myArray = new Object[initialCapacity]; } public void addLast(T object) { - int currrentSize = size(); - if (currrentSize == myArray.length) { - myArray = myState.normalize(currrentSize * 2); + int currentSize = size(); + if (currentSize == myArray.length) { + myArray = normalize(currentSize * 2); myFirst = 0; - myLast = currrentSize; - myState = NORMAL_STATE; + myLast = currentSize; + isInverted = false; + } + myArray[myLast] = object; + myLast++; + if (myLast == myArray.length) { + isInverted = !isInverted; + myLast = 0; } - myState.addLast(object); - } - - public T pullFirst() { - return myState.pullFirst(); } public boolean isEmpty() { @@ -51,79 +49,40 @@ public class Queue { } public int size() { - return myState.calculateSize(); + return isInverted ? myArray.length - myFirst + myLast : myLast - myFirst; } public List toList() { - return Arrays.asList(myState.normalize(size())); + return Arrays.asList(normalize(size())); } - private abstract class QueueState { - public abstract T[] normalize(int capacity); - - public T pullFirst() { - T result = (T)myArray[myFirst]; - myArray[myFirst] = null; - myFirst++; - if (myFirst == myArray.length) { - myFirst = 0; - myState = inverted(); - } - return result; - } - - public void addLast(T object) { - myArray[myLast] = object; - myLast++; - if (myLast == myArray.length) { - myState = inverted(); - myLast = 0; - } - } - - protected abstract QueueState inverted(); - - public abstract int calculateSize(); - - protected int copyFromTo(int first, int last, T[] result, int destPos) { - int length = last - first; - System.arraycopy(myArray, first, result, destPos, length); - return length; + public T pullFirst() { + T result = (T)myArray[myFirst]; + myArray[myFirst] = null; + myFirst++; + if (myFirst == myArray.length) { + myFirst = 0; + isInverted = !isInverted; } + return result; } - private class NormalState extends QueueState { - public T[] normalize(int capacity) { - T[] result = (T[])new Object[capacity]; - copyFromTo(myFirst, myLast, result, 0); - return result; - } - - protected QueueState inverted() { - return INVERTED_STATE; - } - - public int calculateSize() { - return myLast - myFirst; - } - - + private int copyFromTo(int first, int last, T[] result, int destPos) { + int length = last - first; + System.arraycopy(myArray, first, result, destPos, length); + return length; } - private class InvertedState extends QueueState { - public T[] normalize(int capasity) { - T[] result = (T[])new Object[capasity]; - int tailLength = copyFromTo(myFirst, myArray.length, result, 0); - copyFromTo(0, myLast, result, tailLength); - return result; + private T[] normalize(int capacity) { + T[] result = (T[])new Object[capacity]; + int tailLength; + if (isInverted) { + tailLength = copyFromTo(myFirst, myArray.length, result, 0); } - - protected QueueState inverted() { - return NORMAL_STATE; - } - - public int calculateSize() { - return myArray.length - myFirst + myLast; + else { + tailLength = 0; } + copyFromTo(0, myLast, result, tailLength); + return result; } }