Program: 28174
Project: 28174
Buggy source:
/** 
 * Try to minimize conditions expressions, as there are additional assumptions that can be made when it is known that the final result is a boolean. The following transformations are done recursively: !(x||y) --> !x&&!y !(x&&y) --> !x||!y !!x     --> x Thus: !(x&&!y) --> !x||!!y --> !x||y Returns the replacement for n, or the original if no change was made
 */
private Node tryMinimizeCondition(Node n){
  Node parent=n.getParent();
switch (n.getType()) {
case Token.NOT:
    Node first=n.getFirstChild();
switch (first.getType()) {
case Token.NOT:
{
      Node newRoot=first.removeFirstChild();
      parent.replaceChild(n,newRoot);
      reportCodeChange();
      return newRoot;
    }
case Token.AND:
case Token.OR:
{
    Node leftParent=first.getFirstChild();
    Node rightParent=first.getLastChild();
    if (leftParent.getType() == Token.NOT && rightParent.getType() == Token.NOT) {
      Node left=leftParent.removeFirstChild();
      Node right=rightParent.removeFirstChild();
      int newOp=(first.getType() == Token.AND) ? Token.OR : Token.AND;
      Node newRoot=new Node(newOp,left,right);
      parent.replaceChild(n,newRoot);
      reportCodeChange();
      return newRoot;
    }
  }
break;
default :
TernaryValue nVal=NodeUtil.getBooleanValue(first);
if (nVal != TernaryValue.UNKNOWN) {
boolean result=nVal.not().toBoolean(true);
int equivalentResult=result ? 1 : 0;
return maybeReplaceChildWithNumber(n,parent,equivalentResult);
}
}
return n;
case Token.OR:
case Token.AND:
{
Node left=n.getFirstChild();
Node right=n.getLastChild();
left=tryMinimizeCondition(left);
right=tryMinimizeCondition(right);
TernaryValue rightVal=NodeUtil.getBooleanValue(right);
if (NodeUtil.getBooleanValue(right) != TernaryValue.UNKNOWN) {
int type=n.getType();
Node replacement=null;
boolean rval=rightVal.toBoolean(true);
if (type == Token.OR && !rval || type == Token.AND && rval) {
replacement=left;
}
 else if (!mayHaveSideEffects(left)) {
replacement=right;
}
if (replacement != null) {
n.detachChildren();
parent.replaceChild(n,replacement);
reportCodeChange();
return replacement;
}
}
return n;
}
case Token.HOOK:
{
Node condition=n.getFirstChild();
Node trueNode=n.getFirstChild().getNext();
Node falseNode=n.getLastChild();
trueNode=tryMinimizeCondition(trueNode);
falseNode=tryMinimizeCondition(falseNode);
Node replacement=null;
if (NodeUtil.getBooleanValue(trueNode) == TernaryValue.TRUE && NodeUtil.getBooleanValue(falseNode) == TernaryValue.FALSE) {
condition.detachFromParent();
replacement=condition;
}
 else if (NodeUtil.getBooleanValue(trueNode) == TernaryValue.FALSE && NodeUtil.getBooleanValue(falseNode) == TernaryValue.TRUE) {
condition.detachFromParent();
replacement=new Node(Token.NOT,condition);
}
 else if (NodeUtil.getBooleanValue(trueNode) == TernaryValue.TRUE) {
n.detachChildren();
replacement=new Node(Token.OR,condition,falseNode);
}
 else if (NodeUtil.getBooleanValue(falseNode) == TernaryValue.FALSE) {
n.detachChildren();
replacement=new Node(Token.AND,condition,trueNode);
}
if (replacement != null) {
parent.replaceChild(n,replacement);
n=replacement;
reportCodeChange();
}
return n;
}
default :
TernaryValue nVal=NodeUtil.getBooleanValue(n);
if (nVal != TernaryValue.UNKNOWN) {
boolean result=nVal.toBoolean(true);
int equivalentResult=result ? 1 : 0;
return maybeReplaceChildWithNumber(n,parent,equivalentResult);
}
return n;
}
}

Fixed version (ground truth):
/** 
 * Try to minimize conditions expressions, as there are additional assumptions that can be made when it is known that the final result is a boolean. The following transformations are done recursively: !(x||y) --> !x&&!y !(x&&y) --> !x||!y !!x     --> x Thus: !(x&&!y) --> !x||!!y --> !x||y Returns the replacement for n, or the original if no change was made
 */
private Node tryMinimizeCondition(Node n){
  Node parent=n.getParent();
switch (n.getType()) {
case Token.NOT:
    Node first=n.getFirstChild();
switch (first.getType()) {
case Token.NOT:
{
      Node newRoot=first.removeFirstChild();
      parent.replaceChild(n,newRoot);
      reportCodeChange();
      return newRoot;
    }
case Token.AND:
case Token.OR:
{
    Node leftParent=first.getFirstChild();
    Node rightParent=first.getLastChild();
    Node left, right;
    if (leftParent.getType() != Token.NOT && rightParent.getType() != Token.NOT) {
      int op_precedence=NodeUtil.precedence(first.getType());
      if ((isLowerPrecedence(leftParent,NOT_PRECEDENCE) && isHigherPrecedence(leftParent,op_precedence)) || (isLowerPrecedence(rightParent,NOT_PRECEDENCE) && isHigherPrecedence(rightParent,op_precedence))) {
        return n;
      }
    }
    if (leftParent.getType() == Token.NOT) {
      left=leftParent.removeFirstChild();
    }
 else {
      leftParent.detachFromParent();
      left=new Node(Token.NOT,leftParent).copyInformationFrom(leftParent);
    }
    if (rightParent.getType() == Token.NOT) {
      right=rightParent.removeFirstChild();
    }
 else {
      rightParent.detachFromParent();
      right=new Node(Token.NOT,rightParent).copyInformationFrom(rightParent);
    }
    int newOp=(first.getType() == Token.AND) ? Token.OR : Token.AND;
    Node newRoot=new Node(newOp,left,right);
    parent.replaceChild(n,newRoot);
    reportCodeChange();
    return newRoot;
  }
default :
TernaryValue nVal=NodeUtil.getBooleanValue(first);
if (nVal != TernaryValue.UNKNOWN) {
boolean result=nVal.not().toBoolean(true);
int equivalentResult=result ? 1 : 0;
return maybeReplaceChildWithNumber(n,parent,equivalentResult);
}
}
return n;
case Token.OR:
case Token.AND:
{
Node left=n.getFirstChild();
Node right=n.getLastChild();
left=tryMinimizeCondition(left);
right=tryMinimizeCondition(right);
TernaryValue rightVal=NodeUtil.getBooleanValue(right);
if (NodeUtil.getBooleanValue(right) != TernaryValue.UNKNOWN) {
int type=n.getType();
Node replacement=null;
boolean rval=rightVal.toBoolean(true);
if (type == Token.OR && !rval || type == Token.AND && rval) {
replacement=left;
}
 else if (!mayHaveSideEffects(left)) {
replacement=right;
}
if (replacement != null) {
n.detachChildren();
parent.replaceChild(n,replacement);
reportCodeChange();
return replacement;
}
}
return n;
}
case Token.HOOK:
{
Node condition=n.getFirstChild();
Node trueNode=n.getFirstChild().getNext();
Node falseNode=n.getLastChild();
trueNode=tryMinimizeCondition(trueNode);
falseNode=tryMinimizeCondition(falseNode);
Node replacement=null;
if (NodeUtil.getBooleanValue(trueNode) == TernaryValue.TRUE && NodeUtil.getBooleanValue(falseNode) == TernaryValue.FALSE) {
condition.detachFromParent();
replacement=condition;
}
 else if (NodeUtil.getBooleanValue(trueNode) == TernaryValue.FALSE && NodeUtil.getBooleanValue(falseNode) == TernaryValue.TRUE) {
condition.detachFromParent();
replacement=new Node(Token.NOT,condition);
}
 else if (NodeUtil.getBooleanValue(trueNode) == TernaryValue.TRUE) {
n.detachChildren();
replacement=new Node(Token.OR,condition,falseNode);
}
 else if (NodeUtil.getBooleanValue(falseNode) == TernaryValue.FALSE) {
n.detachChildren();
replacement=new Node(Token.AND,condition,trueNode);
}
if (replacement != null) {
parent.replaceChild(n,replacement);
n=replacement;
reportCodeChange();
}
return n;
}
default :
TernaryValue nVal=NodeUtil.getBooleanValue(n);
if (nVal != TernaryValue.UNKNOWN) {
boolean result=nVal.toBoolean(true);
int equivalentResult=result ? 1 : 0;
return maybeReplaceChildWithNumber(n,parent,equivalentResult);
}
return n;
}
}