Program: 27410
Project: 27410
Buggy source:
/** 
 * If the variable is declared more than once in a basic block, generate a warning. Also check if a variable is used in a given scope before it is declared, which suggest a likely error. Relies on the fact that references is in parse-tree order.
 */
private void checkVar(Var v,List<Reference> references){
  blocksWithDeclarations.clear();
  boolean isDeclaredInScope=false;
  boolean isUnhoistedNamedFunction=false;
  boolean hasErrors=false;
  boolean isRead=false;
  Reference hoistedFn=null;
  Reference unusedAssignment=null;
  for (  Reference reference : references) {
    if (reference.isHoistedFunction()) {
      blocksWithDeclarations.add(reference.getBasicBlock());
      isDeclaredInScope=true;
      hoistedFn=reference;
      break;
    }
 else     if (NodeUtil.isFunctionDeclaration(reference.getNode().getParent())) {
      isUnhoistedNamedFunction=true;
    }
  }
  for (  Reference reference : references) {
    if (reference == hoistedFn) {
      continue;
    }
    BasicBlock basicBlock=reference.getBasicBlock();
    boolean isDeclaration=reference.isDeclaration();
    Node referenceNode=reference.getNode();
    boolean isAssignment=isDeclaration || reference.isLvalue();
    boolean allowDupe=VarCheck.hasDuplicateDeclarationSuppression(referenceNode,v);
    boolean letConstShadowsVar=v.getParentNode().isVar() && (reference.isLetDeclaration() || reference.isConstDeclaration());
    boolean isVarNodeSameAsReferenceNode=v.getNode() == reference.getNode();
    boolean shadowCatchVar=isDeclaration && compiler.getLanguageMode().isEs6OrHigher() && v.getParentNode().isCatch()&& !isVarNodeSameAsReferenceNode;
    boolean shadowParam=isDeclaration && v.isParam() && NodeUtil.isBlockScopedDeclaration(referenceNode)&& v.getScope() == reference.getScope().getParent();
    boolean shadowDetected=false;
    if (isDeclaration && !allowDupe) {
      for (      BasicBlock declaredBlock : blocksWithDeclarations) {
        if (declaredBlock.provablyExecutesBefore(basicBlock)) {
          shadowDetected=true;
          DiagnosticType diagnosticType;
          Node warningNode=referenceNode;
          if (v.isLet() || v.isConst() || v.isClass()|| letConstShadowsVar|| shadowCatchVar|| shadowParam) {
            diagnosticType=REDECLARED_VARIABLE_ERROR;
          }
 else           if (reference.getNode().getParent().isCatch() || allowDupe) {
            return;
          }
 else {
            diagnosticType=v.getScope().isGlobal() ? VarCheck.VAR_MULTIPLY_DECLARED_ERROR : REDECLARED_VARIABLE;
            if (isVarNodeSameAsReferenceNode && hoistedFn != null && v.name.equals(hoistedFn.getNode().getString())) {
              warningNode=hoistedFn.getNode();
            }
          }
          compiler.report(JSError.make(warningNode,diagnosticType,v.name,v.input != null ? v.input.getName() : "String_Node_Str"));
          hasErrors=true;
          break;
        }
      }
    }
    if (!shadowDetected && isDeclaration && (letConstShadowsVar || shadowCatchVar)&& v.getScope() == reference.getScope()) {
      compiler.report(JSError.make(referenceNode,REDECLARED_VARIABLE_ERROR,v.name));
    }
    if (isAssignment) {
      Reference decl=references.get(0);
      Node declNode=decl.getNode();
      boolean lhsOfForInLoop=(NodeUtil.isForIn(declNode.getParent()) && declNode == declNode.getParent().getFirstChild()) || (NodeUtil.isForIn(declNode.getGrandparent()) && declNode.getParent().getParent().getFirstChild().getFirstChild() == declNode);
      if (decl.getScope().isLocal() && (decl.isVarDeclaration() || decl.isLetDeclaration() || decl.isConstDeclaration()) && !decl.getNode().isFromExterns()&& !lhsOfForInLoop) {
        unusedAssignment=reference;
      }
      if ((reference.getParent().isDec() || reference.getParent().isInc()) && NodeUtil.isExpressionResultUsed(reference.getNode())) {
        isRead=true;
      }
    }
 else {
      isRead=true;
    }
    if (isUnhoistedNamedFunction && !isDeclaration && isDeclaredInScope) {
      for (      BasicBlock declaredBlock : blocksWithDeclarations) {
        if (!declaredBlock.provablyExecutesBefore(basicBlock)) {
          compiler.report(JSError.make(referenceNode,AMBIGUOUS_FUNCTION_DECL,v.name));
          hasErrors=true;
          break;
        }
      }
    }
    boolean isUndeclaredReference=false;
    if (!isDeclaration && !isDeclaredInScope) {
      if (!referenceNode.isFromExterns()) {
        Node grandparent=reference.getGrandparent();
        if ((v.isVar() && grandparent.isName() && grandparent.getString().equals(v.name))) {
          continue;
        }
        if (reference.getScope() == v.scope && !v.getName().equals("String_Node_Str")) {
          isUndeclaredReference=true;
          compiler.report(JSError.make(reference.getNode(),(v.isLet() || v.isConst() || v.isClass()|| v.isParam()) ? EARLY_REFERENCE_ERROR : EARLY_REFERENCE,v.name));
          hasErrors=true;
        }
      }
    }
    if (!isDeclaration && !isUndeclaredReference && v.isConst()&& reference.isLvalue()) {
      compiler.report(JSError.make(referenceNode,REASSIGNED_CONSTANT,v.name));
    }
    if (isDeclaration && !reference.isVarDeclaration() && reference.getGrandparent().isAddedBlock()) {
      compiler.report(JSError.make(referenceNode,DECLARATION_NOT_DIRECTLY_IN_BLOCK,v.name));
    }
    if (isDeclaration) {
      blocksWithDeclarations.add(basicBlock);
      isDeclaredInScope=true;
    }
  }
  if (unusedAssignment != null && !isRead && !hasErrors) {
    boolean inGoogScope=false;
    Scope s=v.getScope();
    Node function=null;
    if (s.isFunctionBlockScope()) {
      function=s.getRootNode().getParent();
    }
 else     if (s.isFunctionScope()) {
      function=s.getRootNode();
    }
    if (function != null) {
      Node callee=function.getParent().getChildBefore(function);
      inGoogScope=callee != null && callee.matchesQualifiedName("String_Node_Str");
    }
    if (!inGoogScope) {
      compiler.report(JSError.make(unusedAssignment.getNode(),UNUSED_LOCAL_ASSIGNMENT,v.name));
    }
  }
}

Fixed version (ground truth):
/** 
 * If the variable is declared more than once in a basic block, generate a warning. Also check if a variable is used in a given scope before it is declared, which suggest a likely error. Relies on the fact that references is in parse-tree order.
 */
private void checkVar(Var v,List<Reference> references){
  blocksWithDeclarations.clear();
  boolean isDeclaredInScope=false;
  boolean isUnhoistedNamedFunction=false;
  boolean hasErrors=false;
  boolean isRead=false;
  Reference hoistedFn=null;
  Reference unusedAssignment=null;
  for (  Reference reference : references) {
    if (reference.isHoistedFunction()) {
      blocksWithDeclarations.add(reference.getBasicBlock());
      isDeclaredInScope=true;
      hoistedFn=reference;
      break;
    }
 else     if (NodeUtil.isFunctionDeclaration(reference.getNode().getParent())) {
      isUnhoistedNamedFunction=true;
    }
  }
  for (  Reference reference : references) {
    if (reference == hoistedFn) {
      continue;
    }
    BasicBlock basicBlock=reference.getBasicBlock();
    boolean isDeclaration=reference.isDeclaration();
    Node referenceNode=reference.getNode();
    boolean isAssignment=isDeclaration || reference.isLvalue();
    boolean allowDupe=VarCheck.hasDuplicateDeclarationSuppression(referenceNode,v);
    boolean letConstShadowsVar=v.getParentNode().isVar() && (reference.isLetDeclaration() || reference.isConstDeclaration());
    boolean isVarNodeSameAsReferenceNode=v.getNode() == reference.getNode();
    boolean shadowCatchVar=isDeclaration && compiler.getLanguageMode().isEs6OrHigher() && v.getParentNode().isCatch()&& !isVarNodeSameAsReferenceNode;
    boolean shadowParam=isDeclaration && v.isParam() && NodeUtil.isBlockScopedDeclaration(referenceNode)&& v.getScope() == reference.getScope().getParent();
    boolean shadowDetected=false;
    if (isDeclaration && !allowDupe) {
      for (      BasicBlock declaredBlock : blocksWithDeclarations) {
        if (declaredBlock.provablyExecutesBefore(basicBlock)) {
          shadowDetected=true;
          DiagnosticType diagnosticType;
          Node warningNode=referenceNode;
          if (v.isLet() || v.isConst() || v.isClass()|| letConstShadowsVar|| shadowCatchVar|| shadowParam) {
            diagnosticType=REDECLARED_VARIABLE_ERROR;
          }
 else           if (reference.getNode().getParent().isCatch() || allowDupe) {
            return;
          }
 else {
            diagnosticType=v.getScope().isGlobal() ? VarCheck.VAR_MULTIPLY_DECLARED_ERROR : REDECLARED_VARIABLE;
            if (isVarNodeSameAsReferenceNode && hoistedFn != null && v.name.equals(hoistedFn.getNode().getString())) {
              warningNode=hoistedFn.getNode();
            }
          }
          compiler.report(JSError.make(warningNode,diagnosticType,v.name,v.input != null ? v.input.getName() : "String_Node_Str"));
          hasErrors=true;
          break;
        }
      }
    }
    if (!shadowDetected && isDeclaration && (letConstShadowsVar || shadowCatchVar)&& v.getScope() == reference.getScope()) {
      compiler.report(JSError.make(referenceNode,REDECLARED_VARIABLE_ERROR,v.name));
    }
    if (isAssignment) {
      Reference decl=references.get(0);
      Node declNode=decl.getNode();
      Node gp=declNode.getGrandparent();
      boolean lhsOfForInLoop=NodeUtil.isForIn(gp) && gp.getFirstFirstChild() == declNode;
      if (decl.getScope().isLocal() && (decl.isVarDeclaration() || decl.isLetDeclaration() || decl.isConstDeclaration()) && !decl.getNode().isFromExterns()&& !lhsOfForInLoop) {
        unusedAssignment=reference;
      }
      if ((reference.getParent().isDec() || reference.getParent().isInc()) && NodeUtil.isExpressionResultUsed(reference.getNode())) {
        isRead=true;
      }
    }
 else {
      isRead=true;
    }
    if (isUnhoistedNamedFunction && !isDeclaration && isDeclaredInScope) {
      for (      BasicBlock declaredBlock : blocksWithDeclarations) {
        if (!declaredBlock.provablyExecutesBefore(basicBlock)) {
          compiler.report(JSError.make(referenceNode,AMBIGUOUS_FUNCTION_DECL,v.name));
          hasErrors=true;
          break;
        }
      }
    }
    boolean isUndeclaredReference=false;
    if (!isDeclaration && !isDeclaredInScope) {
      if (!referenceNode.isFromExterns()) {
        Node grandparent=reference.getGrandparent();
        if ((v.isVar() && grandparent.isName() && grandparent.getString().equals(v.name))) {
          continue;
        }
        if (reference.getScope() == v.scope && !v.getName().equals("String_Node_Str")) {
          isUndeclaredReference=true;
          compiler.report(JSError.make(reference.getNode(),(v.isLet() || v.isConst() || v.isClass()|| v.isParam()) ? EARLY_REFERENCE_ERROR : EARLY_REFERENCE,v.name));
          hasErrors=true;
        }
      }
    }
    if (!isDeclaration && !isUndeclaredReference && v.isConst()&& reference.isLvalue()) {
      compiler.report(JSError.make(referenceNode,REASSIGNED_CONSTANT,v.name));
    }
    if (isDeclaration && !reference.isVarDeclaration() && reference.getGrandparent().isAddedBlock()) {
      compiler.report(JSError.make(referenceNode,DECLARATION_NOT_DIRECTLY_IN_BLOCK,v.name));
    }
    if (isDeclaration) {
      blocksWithDeclarations.add(basicBlock);
      isDeclaredInScope=true;
    }
  }
  if (unusedAssignment != null && !isRead && !hasErrors) {
    boolean inGoogScope=false;
    Scope s=v.getScope();
    Node function=null;
    if (s.isFunctionBlockScope()) {
      function=s.getRootNode().getParent();
    }
 else     if (s.isFunctionScope()) {
      function=s.getRootNode();
    }
    if (function != null) {
      Node callee=function.getParent().getChildBefore(function);
      inGoogScope=callee != null && callee.matchesQualifiedName("String_Node_Str");
    }
    if (!inGoogScope) {
      compiler.report(JSError.make(unusedAssignment.getNode(),UNUSED_LOCAL_ASSIGNMENT,v.name));
    }
  }
}