never ending def use
authorAlexey Kudravtsev <cdr@intellij.com>
Fri, 3 Sep 2010 15:32:56 +0000 (19:32 +0400)
committerAlexey Kudravtsev <cdr@intellij.com>
Mon, 6 Sep 2010 08:51:31 +0000 (12:51 +0400)
java/java-impl/src/com/intellij/psi/controlFlow/DefUseUtil.java
java/java-tests/testData/inspection/defUse/Hang/expected.xml [new file with mode: 0644]
java/java-tests/testData/inspection/defUse/Hang/src/Foo.java [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/codeInspection/DefUseTest.java
platform/util/src/com/intellij/util/containers/Queue.java

index 687de99e9b24160aa2cc278f87dc07e3b1609c52..fb05c91b2d72105dca9924277ba3950823ea7d52 100644 (file)
@@ -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<PsiVariable>();
     }
 
-    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<InstructionState> queue = new ArrayList<InstructionState>();
+    Queue<InstructionState> queue = new Queue<InstructionState>(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<PsiElement> 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<PsiElement> 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 (file)
index 0000000..d704d58
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<problems>
+</problems>
+
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 (file)
index 0000000..06b20f8
--- /dev/null
@@ -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;
+    }
+
+}
index 1c7c240ec32b4fcf54bff56de74fbf731a1cbf2a..9dd090b05909208d74d0eb4834bc630449485e1f 100644 (file)
@@ -30,21 +30,14 @@ public class DefUseTest extends InspectionTestCase {
   public void testarrayIndexUsages() throws Exception {
     doTest();
   }
-  /* TODO:
-  public void testSCR28019() throws Exception {
-    doTest();
-  }
-  */
 
-  public void testSCR40364() throws Exception {
-    doTest();
-  }
-
-  public void testArrayLength() throws Exception {
+  // TODO:
+  public void testSCR28019() 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(); }
 }
index 689d851616bc8a9a9b14287df715680c39c85128..79da1445dda401ecab147d1c293c191e8f36eaea 100644 (file)
@@ -19,31 +19,29 @@ import java.util.Arrays;
 import java.util.List;
 
 public class Queue<T> {
-  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<T> {
   }
 
   public int size() {
-    return myState.calculateSize();
+    return isInverted ? myArray.length - myFirst + myLast : myLast - myFirst;
   }
 
   public List<T> 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;
   }
 }