Program: 27116
Project: 27116
Buggy source:
/** 
 * This is the meat of the type checking.  It is basically one big switch, with each case representing one type of parse tree node.  The individual cases are usually pretty straightforward.
 * @param t The node traversal object that supplies context, such as thescope chain to use in name lookups as well as error reporting.
 * @param n The node being visited.
 * @param parent The parent of the node n.
 */
@Override public void visit(NodeTraversal t,Node n,Node parent){
  JSType childType;
  JSType leftType;
  JSType rightType;
  Node left;
  Node right;
  boolean typeable=true;
switch (n.getToken()) {
case CAST:
    Node expr=n.getFirstChild();
  JSType exprType=getJSType(expr);
JSType castType=getJSType(n);
if (!expr.isObjectLit()) {
validator.expectCanCast(t,n,castType,exprType);
}
ensureTyped(t,n,castType);
expr.putProp(Node.TYPE_BEFORE_CAST,exprType);
if (castType.restrictByNotNullOrUndefined().isSubtypeOf(exprType) || expr.isObjectLit()) {
expr.setJSType(castType);
}
break;
case NAME:
typeable=visitName(t,n,parent);
break;
case COMMA:
ensureTyped(t,n,getJSType(n.getLastChild()));
break;
case THIS:
ensureTyped(t,n,t.getTypedScope().getTypeOfThis());
break;
case SUPER:
ensureTyped(t,n);
break;
case NULL:
ensureTyped(t,n,NULL_TYPE);
break;
case NUMBER:
ensureTyped(t,n,NUMBER_TYPE);
break;
case GETTER_DEF:
case SETTER_DEF:
break;
case ARRAYLIT:
ensureTyped(t,n,ARRAY_TYPE);
break;
case REGEXP:
ensureTyped(t,n,REGEXP_TYPE);
break;
case GETPROP:
visitGetProp(t,n);
typeable=!(parent.isAssign() && parent.getFirstChild() == n);
break;
case GETELEM:
visitGetElem(t,n);
typeable=false;
break;
case VAR:
case LET:
case CONST:
visitVar(t,n);
typeable=false;
break;
case NEW:
visitNew(t,n);
break;
case CALL:
visitCall(t,n);
typeable=!parent.isExprResult();
break;
case RETURN:
visitReturn(t,n);
typeable=false;
break;
case YIELD:
visitYield(t,n);
typeable=false;
break;
case DEC:
case INC:
left=n.getFirstChild();
checkPropCreation(t,left);
validator.expectNumber(t,left,getJSType(left),"String_Node_Str");
ensureTyped(t,n,NUMBER_TYPE);
break;
case VOID:
ensureTyped(t,n,VOID_TYPE);
break;
case STRING:
case TYPEOF:
ensureTyped(t,n,STRING_TYPE);
break;
case BITNOT:
childType=getJSType(n.getFirstChild());
if (!childType.matchesNumberContext()) {
report(t,n,BIT_OPERATION,NodeUtil.opToStr(n.getToken()),childType.toString());
}
 else if (this.strictOperatorChecks) {
this.validator.expectNumberStrict(n,childType,"String_Node_Str");
}
ensureTyped(t,n,NUMBER_TYPE);
break;
case POS:
case NEG:
left=n.getFirstChild();
if (n.getToken() == Token.NEG) {
validator.expectNumber(t,left,getJSType(left),"String_Node_Str");
}
ensureTyped(t,n,NUMBER_TYPE);
break;
case EQ:
case NE:
case SHEQ:
case SHNE:
{
left=n.getFirstChild();
right=n.getLastChild();
if (left.isTypeOf()) {
if (right.isString()) {
checkTypeofString(t,right,right.getString());
}
}
 else if (right.isTypeOf() && left.isString()) {
checkTypeofString(t,left,left.getString());
}
leftType=getJSType(left);
rightType=getJSType(right);
JSType leftTypeRestricted=leftType.restrictByNotNullOrUndefined();
JSType rightTypeRestricted=rightType.restrictByNotNullOrUndefined();
TernaryValue result=TernaryValue.UNKNOWN;
if (n.getToken() == Token.EQ || n.isNE()) {
result=leftTypeRestricted.testForEquality(rightTypeRestricted);
if (n.isNE()) {
result=result.not();
}
}
 else {
if (!leftTypeRestricted.canTestForShallowEqualityWith(rightTypeRestricted)) {
result=n.getToken() == Token.SHEQ ? TernaryValue.FALSE : TernaryValue.TRUE;
}
}
if (result != TernaryValue.UNKNOWN) {
report(t,n,DETERMINISTIC_TEST,leftType.toString(),rightType.toString(),result.toString());
}
ensureTyped(t,n,BOOLEAN_TYPE);
break;
}
case LT:
case LE:
case GT:
case GE:
leftType=getJSType(n.getFirstChild());
rightType=getJSType(n.getLastChild());
if (rightType.isUnknownType()) {
validator.expectStringOrNumber(t,n,leftType,"String_Node_Str");
}
 else if (leftType.isUnknownType()) {
validator.expectStringOrNumber(t,n,leftType,"String_Node_Str");
}
 else if (rightType.isNumber()) {
validator.expectNumber(t,n,leftType,"String_Node_Str");
}
 else if (leftType.isNumber()) {
validator.expectNumber(t,n,rightType,"String_Node_Str");
}
 else if (this.strictOperatorChecks) {
String errorMsg="String_Node_Str";
this.validator.expectMatchingTypes(n,leftType,rightType,errorMsg);
}
 else if (leftType.matchesNumberContext() && rightType.matchesNumberContext()) {
}
 else {
String message="String_Node_Str";
validator.expectString(t,n,leftType,message);
validator.expectNotNullOrUndefined(t,n,leftType,message,getNativeType(STRING_TYPE));
message="String_Node_Str";
validator.expectString(t,n,rightType,message);
validator.expectNotNullOrUndefined(t,n,rightType,message,getNativeType(STRING_TYPE));
}
ensureTyped(t,n,BOOLEAN_TYPE);
break;
case IN:
left=n.getFirstChild();
right=n.getLastChild();
rightType=getJSType(right);
validator.expectString(t,left,getJSType(left),"String_Node_Str");
validator.expectObject(t,n,rightType,"String_Node_Str");
if (rightType.isStruct()) {
report(t,right,IN_USED_WITH_STRUCT);
}
ensureTyped(t,n,BOOLEAN_TYPE);
break;
case INSTANCEOF:
left=n.getFirstChild();
right=n.getLastChild();
rightType=getJSType(right).restrictByNotNullOrUndefined();
validator.expectAnyObject(t,left,getJSType(left),"String_Node_Str");
validator.expectActualObject(t,right,rightType,"String_Node_Str");
ensureTyped(t,n,BOOLEAN_TYPE);
break;
case ASSIGN:
visitAssign(t,n);
typeable=false;
break;
case ASSIGN_LSH:
case ASSIGN_RSH:
case ASSIGN_URSH:
case ASSIGN_DIV:
case ASSIGN_MOD:
case ASSIGN_BITOR:
case ASSIGN_BITXOR:
case ASSIGN_BITAND:
case ASSIGN_SUB:
case ASSIGN_ADD:
case ASSIGN_MUL:
checkPropCreation(t,n.getFirstChild());
case LSH:
case RSH:
case URSH:
case DIV:
case MOD:
case BITOR:
case BITXOR:
case BITAND:
case SUB:
case ADD:
case MUL:
visitBinaryOperator(n.getToken(),t,n);
break;
case TRUE:
case FALSE:
case NOT:
case DELPROP:
ensureTyped(t,n,BOOLEAN_TYPE);
break;
case CASE:
JSType switchType=getJSType(parent.getFirstChild());
JSType caseType=getJSType(n.getFirstChild());
validator.expectSwitchMatchesCase(t,n,switchType,caseType);
typeable=false;
break;
case WITH:
{
Node child=n.getFirstChild();
childType=getJSType(child);
validator.expectObject(t,child,childType,"String_Node_Str");
typeable=false;
break;
}
case MEMBER_FUNCTION_DEF:
ensureTyped(t,n,getJSType(n.getFirstChild()));
break;
case FUNCTION:
visitFunction(t,n);
break;
case PARAM_LIST:
case STRING_KEY:
case LABEL:
case LABEL_NAME:
case SWITCH:
case BREAK:
case CATCH:
case TRY:
case SCRIPT:
case EXPR_RESULT:
case BLOCK:
case ROOT:
case EMPTY:
case DEFAULT_CASE:
case CONTINUE:
case DEBUGGER:
case THROW:
case DO:
case IF:
case WHILE:
case FOR:
typeable=false;
break;
case FOR_IN:
Node obj=n.getSecondChild();
if (getJSType(obj).isStruct()) {
report(t,obj,IN_USED_WITH_STRUCT);
}
typeable=false;
break;
case FOR_OF:
ensureTyped(t,n.getSecondChild());
JSType iterable=getJSType(n.getSecondChild());
JSType autoboxedIterable=iterable.autoboxesTo();
iterable=autoboxedIterable != null ? autoboxedIterable : iterable;
validator.expectIterable(t,n.getSecondChild(),iterable,"String_Node_Str");
typeable=false;
Node loopVarNode=NodeUtil.isNameDeclaration(n.getFirstChild()) ? n.getFirstFirstChild() : n.getFirstChild();
JSType declaredType=loopVarNode.getJSType();
if (declaredType != null) {
JSType actualType=iterable.getTemplateTypeMap().getResolvedTemplateType(typeRegistry.getIterableTemplate());
validator.expectCanAssignTo(t,loopVarNode,declaredType,actualType,"String_Node_Str");
}
break;
case AND:
case HOOK:
case OBJECTLIT:
case OR:
if (n.getJSType() != null) {
ensureTyped(t,n);
}
 else {
if ((n.isObjectLit()) && (parent.getJSType() instanceof EnumType)) {
ensureTyped(t,n,parent.getJSType());
}
 else {
ensureTyped(t,n);
}
}
if (n.isObjectLit()) {
JSType typ=getJSType(n);
for (Node key : n.children()) {
visitObjLitKey(t,key,n,typ);
}
}
break;
default :
report(t,n,UNEXPECTED_TOKEN,n.getToken().toString());
ensureTyped(t,n);
break;
}
typeable=typeable && !inExterns;
if (typeable) {
doPercentTypedAccounting(t,n);
}
checkJsdocInfoContainsObjectWithBadKey(t,n);
}

Fixed version (ground truth):
/** 
 * This is the meat of the type checking.  It is basically one big switch, with each case representing one type of parse tree node.  The individual cases are usually pretty straightforward.
 * @param t The node traversal object that supplies context, such as thescope chain to use in name lookups as well as error reporting.
 * @param n The node being visited.
 * @param parent The parent of the node n.
 */
@Override public void visit(NodeTraversal t,Node n,Node parent){
  JSType childType;
  JSType leftType;
  JSType rightType;
  Node left;
  Node right;
  boolean typeable=true;
switch (n.getToken()) {
case CAST:
    Node expr=n.getFirstChild();
  JSType exprType=getJSType(expr);
JSType castType=getJSType(n);
if (!expr.isObjectLit()) {
validator.expectCanCast(t,n,castType,exprType);
}
ensureTyped(t,n,castType);
expr.putProp(Node.TYPE_BEFORE_CAST,exprType);
if (castType.restrictByNotNullOrUndefined().isSubtypeOf(exprType) || expr.isObjectLit()) {
expr.setJSType(castType);
}
break;
case NAME:
typeable=visitName(t,n,parent);
break;
case COMMA:
ensureTyped(t,n,getJSType(n.getLastChild()));
break;
case THIS:
ensureTyped(t,n,t.getTypedScope().getTypeOfThis());
break;
case SUPER:
ensureTyped(t,n);
break;
case NULL:
ensureTyped(t,n,NULL_TYPE);
break;
case NUMBER:
ensureTyped(t,n,NUMBER_TYPE);
break;
case GETTER_DEF:
case SETTER_DEF:
break;
case ARRAYLIT:
ensureTyped(t,n,ARRAY_TYPE);
break;
case REGEXP:
ensureTyped(t,n,REGEXP_TYPE);
break;
case GETPROP:
visitGetProp(t,n);
typeable=!(parent.isAssign() && parent.getFirstChild() == n);
break;
case GETELEM:
visitGetElem(t,n);
typeable=false;
break;
case VAR:
case LET:
case CONST:
visitVar(t,n);
typeable=false;
break;
case NEW:
visitNew(t,n);
break;
case CALL:
visitCall(t,n);
typeable=!parent.isExprResult();
break;
case RETURN:
visitReturn(t,n);
typeable=false;
break;
case YIELD:
visitYield(t,n);
typeable=false;
break;
case DEC:
case INC:
left=n.getFirstChild();
checkPropCreation(t,left);
validator.expectNumber(t,left,getJSType(left),"String_Node_Str");
ensureTyped(t,n,NUMBER_TYPE);
break;
case VOID:
ensureTyped(t,n,VOID_TYPE);
break;
case STRING:
case TYPEOF:
ensureTyped(t,n,STRING_TYPE);
break;
case BITNOT:
childType=getJSType(n.getFirstChild());
if (!childType.matchesNumberContext()) {
report(t,n,BIT_OPERATION,NodeUtil.opToStr(n.getToken()),childType.toString());
}
 else if (this.strictOperatorChecks) {
this.validator.expectNumberStrict(n,childType,"String_Node_Str");
}
ensureTyped(t,n,NUMBER_TYPE);
break;
case POS:
case NEG:
left=n.getFirstChild();
if (n.getToken() == Token.NEG) {
validator.expectNumber(t,left,getJSType(left),"String_Node_Str");
}
ensureTyped(t,n,NUMBER_TYPE);
break;
case EQ:
case NE:
case SHEQ:
case SHNE:
{
left=n.getFirstChild();
right=n.getLastChild();
if (left.isTypeOf()) {
if (right.isString()) {
checkTypeofString(t,right,right.getString());
}
}
 else if (right.isTypeOf() && left.isString()) {
checkTypeofString(t,left,left.getString());
}
leftType=getJSType(left);
rightType=getJSType(right);
JSType leftTypeRestricted=leftType.restrictByNotNullOrUndefined();
JSType rightTypeRestricted=rightType.restrictByNotNullOrUndefined();
TernaryValue result=TernaryValue.UNKNOWN;
if (n.getToken() == Token.EQ || n.isNE()) {
result=leftTypeRestricted.testForEquality(rightTypeRestricted);
if (n.isNE()) {
result=result.not();
}
}
 else {
if (!leftTypeRestricted.canTestForShallowEqualityWith(rightTypeRestricted)) {
result=n.getToken() == Token.SHEQ ? TernaryValue.FALSE : TernaryValue.TRUE;
}
}
if (result != TernaryValue.UNKNOWN) {
report(t,n,DETERMINISTIC_TEST,leftType.toString(),rightType.toString(),result.toString());
}
ensureTyped(t,n,BOOLEAN_TYPE);
break;
}
case LT:
case LE:
case GT:
case GE:
leftType=getJSType(n.getFirstChild());
rightType=getJSType(n.getLastChild());
if (rightType.isUnknownType()) {
validator.expectStringOrNumber(t,n,leftType,"String_Node_Str");
}
 else if (leftType.isUnknownType()) {
validator.expectStringOrNumber(t,n,leftType,"String_Node_Str");
}
 else if (rightType.isNumber()) {
validator.expectNumber(t,n,leftType,"String_Node_Str");
}
 else if (leftType.isNumber()) {
validator.expectNumber(t,n,rightType,"String_Node_Str");
}
 else if (this.strictOperatorChecks) {
String errorMsg="String_Node_Str";
this.validator.expectMatchingTypes(n,leftType,rightType,errorMsg);
}
 else if (leftType.matchesNumberContext() && rightType.matchesNumberContext()) {
}
 else {
String message="String_Node_Str";
validator.expectString(t,n,leftType,message);
validator.expectNotNullOrUndefined(t,n,leftType,message,getNativeType(STRING_TYPE));
message="String_Node_Str";
validator.expectString(t,n,rightType,message);
validator.expectNotNullOrUndefined(t,n,rightType,message,getNativeType(STRING_TYPE));
}
ensureTyped(t,n,BOOLEAN_TYPE);
break;
case IN:
left=n.getFirstChild();
right=n.getLastChild();
rightType=getJSType(right);
validator.expectString(t,left,getJSType(left),"String_Node_Str");
validator.expectObject(t,n,rightType,"String_Node_Str");
if (rightType.isStruct()) {
report(t,right,IN_USED_WITH_STRUCT);
}
ensureTyped(t,n,BOOLEAN_TYPE);
break;
case INSTANCEOF:
left=n.getFirstChild();
right=n.getLastChild();
rightType=getJSType(right).restrictByNotNullOrUndefined();
validator.expectAnyObject(t,left,getJSType(left),"String_Node_Str");
validator.expectActualObject(t,right,rightType,"String_Node_Str");
ensureTyped(t,n,BOOLEAN_TYPE);
break;
case ASSIGN:
visitAssign(t,n);
typeable=false;
break;
case ASSIGN_LSH:
case ASSIGN_RSH:
case ASSIGN_URSH:
case ASSIGN_DIV:
case ASSIGN_MOD:
case ASSIGN_BITOR:
case ASSIGN_BITXOR:
case ASSIGN_BITAND:
case ASSIGN_SUB:
case ASSIGN_ADD:
case ASSIGN_MUL:
checkPropCreation(t,n.getFirstChild());
case LSH:
case RSH:
case URSH:
case DIV:
case MOD:
case BITOR:
case BITXOR:
case BITAND:
case SUB:
case ADD:
case MUL:
visitBinaryOperator(n.getToken(),t,n);
break;
case TRUE:
case FALSE:
case NOT:
case DELPROP:
ensureTyped(t,n,BOOLEAN_TYPE);
break;
case CASE:
JSType switchType=getJSType(parent.getFirstChild());
JSType caseType=getJSType(n.getFirstChild());
validator.expectSwitchMatchesCase(t,n,switchType,caseType);
typeable=false;
break;
case WITH:
{
Node child=n.getFirstChild();
childType=getJSType(child);
validator.expectObject(t,child,childType,"String_Node_Str");
typeable=false;
break;
}
case MEMBER_FUNCTION_DEF:
ensureTyped(t,n,getJSType(n.getFirstChild()));
break;
case FUNCTION:
visitFunction(t,n);
break;
case PARAM_LIST:
case STRING_KEY:
case LABEL:
case LABEL_NAME:
case SWITCH:
case BREAK:
case CATCH:
case TRY:
case SCRIPT:
case EXPR_RESULT:
case BLOCK:
case ROOT:
case EMPTY:
case DEFAULT_CASE:
case CONTINUE:
case DEBUGGER:
case THROW:
case DO:
case IF:
case WHILE:
case FOR:
typeable=false;
break;
case FOR_IN:
Node obj=n.getSecondChild();
if (getJSType(obj).isStruct()) {
report(t,obj,IN_USED_WITH_STRUCT);
}
typeable=false;
break;
case FOR_OF:
ensureTyped(t,n.getSecondChild());
JSType iterable=getJSType(n.getSecondChild());
JSType autoboxedIterable=iterable.autoboxesTo();
iterable=autoboxedIterable != null ? autoboxedIterable : iterable;
validator.expectIterable(t,n.getSecondChild(),iterable,"String_Node_Str");
typeable=false;
Node loopVarNode=NodeUtil.isNameDeclaration(n.getFirstChild()) ? n.getFirstFirstChild() : n.getFirstChild();
JSType declaredType=loopVarNode.getJSType();
if (declaredType != null) {
JSType actualType=iterable.getTemplateTypeMap().getResolvedTemplateType(typeRegistry.getIterableTemplate());
validator.expectCanAssignTo(t,loopVarNode,actualType,declaredType,"String_Node_Str");
}
break;
case AND:
case HOOK:
case OBJECTLIT:
case OR:
if (n.getJSType() != null) {
ensureTyped(t,n);
}
 else {
if ((n.isObjectLit()) && (parent.getJSType() instanceof EnumType)) {
ensureTyped(t,n,parent.getJSType());
}
 else {
ensureTyped(t,n);
}
}
if (n.isObjectLit()) {
JSType typ=getJSType(n);
for (Node key : n.children()) {
visitObjLitKey(t,key,n,typ);
}
}
break;
default :
report(t,n,UNEXPECTED_TOKEN,n.getToken().toString());
ensureTyped(t,n);
break;
}
typeable=typeable && !inExterns;
if (typeable) {
doPercentTypedAccounting(t,n);
}
checkJsdocInfoContainsObjectWithBadKey(t,n);
}