Program: 5220
Project: 5220
Buggy source:
/** 
 * Finds the set of LALR Items that are in the epsilon-closure of the specified set of start items.
 * @param startItems - the set of kernel items to calculate the closure of
 * @return the set of closure items that must be added to the kernel set to produce the closure
 */
public Map<TypeUseEntry,LALRItem> calculateClosureItems(Collection<LALRItem> startItems){
  Deque<LALRItem> queue=new LinkedList<LALRItem>();
  queue.addAll(startItems);
  Map<TypeUseEntry,LALRItem> result=new HashMap<TypeUseEntry,LALRItem>();
  Map<TypeUseEntry,LALRItem> visited=new HashMap<TypeUseEntry,LALRItem>();
  while (!queue.isEmpty()) {
    LALRItem item=queue.pollFirst();
    LALRItem visitedItem=visited.get(item.getNextTypeUse());
    if (visitedItem != null && visitedItem.containsLookaheads(item)) {
      continue;
    }
    LALRItem itemCopy=new LALRItem(item);
    visited.put(itemCopy.getNextTypeUse(),itemCopy);
    int offset=item.getOffset();
    LALRItem resultItem=new LALRItem(item.getRule(),item.getProductionIndex(),offset);
    LALRItem existing=result.get(resultItem.getNextTypeUse());
    if (existing != null) {
      existing.addLookaheads(item.getLookaheads());
      queue.addLast(existing);
    }
 else {
      resultItem.addLookaheads(item.getLookaheads());
      result.put(resultItem.getNextTypeUse(),resultItem);
    }
    Object[] production=item.getProduction();
    if (offset == production.length) {
      continue;
    }
    Rule rule=rules.get(production[offset]);
    if (rule != null) {
      Set<Object> lookaheads=new HashSet<Object>();
      boolean nullable=true;
      for (int lookahead=offset + 1; lookahead < production.length; lookahead++) {
        lookaheads.addAll(getFirstSet(production[lookahead]));
        if (!isNullable(production[lookahead])) {
          nullable=false;
          break;
        }
      }
      if (nullable) {
        lookaheads.addAll(item.getLookaheads());
      }
      Object[][] subProductions=rule.getProductions();
      for (int j=0; j < subProductions.length; j++) {
        LALRItem stackItem=new LALRItem(rule,j,0);
        stackItem.addLookaheads(lookaheads);
        queue.addLast(stackItem);
      }
    }
  }
  Iterator<Entry<TypeUseEntry,LALRItem>> it=result.entrySet().iterator();
  while (it.hasNext()) {
    Entry<TypeUseEntry,LALRItem> entry=it.next();
    if (startItems.contains(entry.getValue())) {
      it.remove();
    }
  }
  return result;
}

Fixed version (ground truth):
/** 
 * Finds the set of LALR Items that are in the epsilon-closure of the specified set of start items.
 * @param startItems - the set of kernel items to calculate the closure of
 * @return the set of closure items that must be added to the kernel set to produce the closure. These will be updated with any additional lookaheads they require
 */
public Map<TypeUseEntry,LALRItem> calculateClosureItems(Collection<LALRItem> startItems){
  Deque<LALRItem> queue=new LinkedList<LALRItem>();
  queue.addAll(startItems);
  Map<TypeUseEntry,LALRItem> result=new HashMap<TypeUseEntry,LALRItem>();
  for (  LALRItem startItem : startItems) {
    result.put(startItem.getNextTypeUse(),startItem);
  }
  Map<TypeUseEntry,LALRItem> visited=new HashMap<TypeUseEntry,LALRItem>();
  while (!queue.isEmpty()) {
    LALRItem item=queue.pollFirst();
    LALRItem visitedItem=visited.get(item.getNextTypeUse());
    if (visitedItem != null && visitedItem.containsLookaheads(item)) {
      continue;
    }
    LALRItem itemCopy=new LALRItem(item);
    visited.put(itemCopy.getNextTypeUse(),itemCopy);
    int offset=item.getOffset();
    LALRItem resultItem=new LALRItem(item.getRule(),item.getProductionIndex(),offset);
    LALRItem existing=result.get(resultItem.getNextTypeUse());
    if (existing != null) {
      existing.addLookaheads(item.getLookaheads());
      queue.addLast(existing);
    }
 else {
      resultItem.addLookaheads(item.getLookaheads());
      result.put(resultItem.getNextTypeUse(),resultItem);
    }
    Object[] production=item.getProduction();
    if (offset == production.length) {
      continue;
    }
    Rule rule=rules.get(production[offset]);
    if (rule != null) {
      Set<Object> lookaheads=new HashSet<Object>();
      boolean nullable=true;
      for (int lookahead=offset + 1; lookahead < production.length; lookahead++) {
        lookaheads.addAll(getFirstSet(production[lookahead]));
        if (!isNullable(production[lookahead])) {
          nullable=false;
          break;
        }
      }
      if (nullable) {
        lookaheads.addAll(item.getLookaheads());
      }
      Object[][] subProductions=rule.getProductions();
      for (int j=0; j < subProductions.length; j++) {
        LALRItem stackItem=new LALRItem(rule,j,0);
        stackItem.addLookaheads(lookaheads);
        queue.addLast(stackItem);
      }
    }
  }
  Iterator<Entry<TypeUseEntry,LALRItem>> it=result.entrySet().iterator();
  while (it.hasNext()) {
    Entry<TypeUseEntry,LALRItem> entry=it.next();
    if (startItems.contains(entry.getValue())) {
      it.remove();
    }
  }
  return result;
}