Program: 32855
Project: 32855
Buggy source:
/** 
 * For implementing the ListChangeListener interface. When the underlying list changes, this notification allows the object to repaint itself or update itself as necessary. <p>This is implemented in two phases. The first phase updates the unsorted indexes of all nodes. The second phase updates the sorted indexes, removing and deleting nodes as necessary. Two phases are necessary because the sorted nodes cannot be inserted until all of the final offsets are known. This means that all offsets must be updated before the first sorted value is updated.
 */
public void notifyListChanges(ListChangeEvent listChanges){
synchronized (getRootList()) {
    updates.beginAtomicChange();
    ArrayList unsortedNodes=new ArrayList();
    ListChangeEvent clonedChanges=new ListChangeEvent(listChanges);
    while (clonedChanges.next()) {
      int unsortedIndex=clonedChanges.getIndex();
      int changeType=clonedChanges.getType();
      if (changeType == ListChangeBlock.INSERT) {
        IndexedTreeNode unsortedNode=unsorted.addByNode(unsortedIndex,this);
        unsortedNodes.add(unsortedNode);
      }
 else       if (changeType == ListChangeBlock.DELETE) {
        IndexedTreeNode unsortedNode=unsorted.getNode(unsortedIndex);
        unsortedNode.removeFromTree();
        unsortedNodes.add(unsortedNode);
      }
 else       if (changeType == ListChangeBlock.UPDATE) {
        IndexedTreeNode unsortedNode=unsorted.getNode(unsortedIndex);
        unsortedNodes.add(unsortedNode);
      }
    }
    Iterator unsortedNodesIterator=unsortedNodes.iterator();
    while (listChanges.next()) {
      int unsortedIndex=listChanges.getIndex();
      int changeType=listChanges.getType();
      IndexedTreeNode unsortedNode=(IndexedTreeNode)unsortedNodesIterator.next();
      if (changeType == ListChangeBlock.INSERT) {
        int sortedIndex=insertByUnsortedNode(unsortedNode);
        updates.appendChange(sortedIndex,ListChangeBlock.INSERT);
      }
 else       if (changeType == ListChangeBlock.DELETE) {
        int sortedIndex=deleteByUnsortedNode(unsortedNode);
        updates.appendChange(sortedIndex,ListChangeBlock.DELETE);
      }
 else       if (changeType == ListChangeBlock.UPDATE) {
        int deleteSortedIndex=deleteByUnsortedNode(unsortedNode);
        int insertSortedIndex=insertByUnsortedNode(unsortedNode);
        if (deleteSortedIndex == insertSortedIndex) {
          updates.appendChange(insertSortedIndex,ListChangeBlock.UPDATE);
        }
 else {
          updates.appendChange(deleteSortedIndex,ListChangeBlock.DELETE);
          updates.appendChange(insertSortedIndex,ListChangeBlock.INSERT);
        }
      }
    }
    updates.commitAtomicChange();
  }
}

Fixed version (ground truth):
/** 
 * For implementing the ListChangeListener interface. When the underlying list changes, this notification allows the object to repaint itself or update itself as necessary. <p>This is implemented in two phases. First, the unsorted index tree is updated so that it maches the source list. This is necessary so that when sorted operations are performed, the comparisons are done with respect to the correct unsorted index. In the second phase, the sorted list is updated with the changes.
 */
public void notifyListChanges(ListChangeEvent listChanges){
synchronized (getRootList()) {
    updates.beginAtomicChange();
    ArrayList unsortedNodes=new ArrayList();
    ArrayList deletedIndices=new ArrayList();
    ListChangeEvent clonedChanges=new ListChangeEvent(listChanges);
    int sortedOffset=0;
    while (clonedChanges.next()) {
      int unsortedIndex=clonedChanges.getIndex();
      int changeType=clonedChanges.getType();
      if (changeType == ListChangeBlock.INSERT) {
        IndexedTreeNode unsortedNode=unsorted.addByNode(unsortedIndex,this);
        unsortedNodes.add(unsortedNode);
        sortedOffset++;
      }
 else       if (changeType == ListChangeBlock.DELETE) {
        IndexedTreeNode unsortedNode=unsorted.getNode(unsortedIndex);
        unsortedNode.removeFromTree();
        int deleteSortedIndex=deleteByUnsortedNode(unsortedNode);
        updates.appendChange(deleteSortedIndex,ListChangeBlock.DELETE);
      }
 else       if (changeType == ListChangeBlock.UPDATE) {
        IndexedTreeNode unsortedNode=unsorted.getNode(unsortedIndex);
        int deleteSortedIndex=deleteByUnsortedNode(unsortedNode) + sortedOffset;
        unsortedNodes.add(unsortedNode);
        deletedIndices.add(new Integer(deleteSortedIndex));
        sortedOffset++;
      }
    }
    if (unsorted.size() != source.size())     throw new IllegalStateException();
    if (sorted.size() + sortedOffset != source.size())     throw new IllegalStateException();
    Iterator unsortedNodesIterator=unsortedNodes.iterator();
    Iterator deletedIndicesIterator=deletedIndices.iterator();
    while (listChanges.next()) {
      int unsortedIndex=listChanges.getIndex();
      int changeType=listChanges.getType();
      if (changeType == ListChangeBlock.INSERT) {
        IndexedTreeNode unsortedNode=(IndexedTreeNode)unsortedNodesIterator.next();
        int sortedIndex=insertByUnsortedNode(unsortedNode);
        updates.appendChange(sortedIndex,ListChangeBlock.INSERT);
      }
 else       if (changeType == ListChangeBlock.DELETE) {
      }
 else       if (changeType == ListChangeBlock.UPDATE) {
        int deleteSortedIndex=((Integer)deletedIndicesIterator.next()).intValue();
        IndexedTreeNode unsortedNode=(IndexedTreeNode)unsortedNodesIterator.next();
        int insertSortedIndex=insertByUnsortedNode(unsortedNode);
        if (deleteSortedIndex == insertSortedIndex) {
          updates.appendChange(insertSortedIndex,ListChangeBlock.UPDATE);
        }
 else {
          updates.appendChange(deleteSortedIndex,ListChangeBlock.DELETE);
          updates.appendChange(insertSortedIndex,ListChangeBlock.INSERT);
        }
      }
    }
    if (deletedIndicesIterator.hasNext())     throw new IllegalStateException();
    if (unsortedNodesIterator.hasNext())     throw new IllegalStateException();
    updates.commitAtomicChange();
  }
}