Program: 53397
Project: 53397
Buggy source:
/** 
 * Determine if <code>invokedFunction</code> can be inlined into <code>callerFunction</code> at callsite <code>x</code>.
 * @return An expression equivalent to <code>x</code>
 */
private JsExpression process(JsInvocation x,JsFunction callerFunction,JsFunction invokedFunction){
  List<JsStatement> statements;
  if (invokedFunction.getBody() != null) {
    statements=Lists.newArrayList(invokedFunction.getBody().getStatements());
  }
 else {
    statements=Collections.emptyList();
  }
  List<JsExpression> hoisted=Lists.newArrayListWithCapacity(statements.size());
  JsExpression thisExpr=((JsNameRef)x.getQualifier()).getQualifier();
  HoistedNameVisitor hoistedNameVisitor=new HoistedNameVisitor(callerFunction.getScope(),invokedFunction.getScope());
  boolean sawReturnStatement=false;
  for (  JsStatement statement : statements) {
    if (sawReturnStatement) {
      return x;
    }
    JsExpression h=hoistedExpression(statement);
    if (h == null) {
      return x;
    }
    hoistedNameVisitor.accept(statement);
    if (isReturnStatement(statement)) {
      sawReturnStatement=true;
      hoisted.add(h);
    }
 else     if (hasSideEffects(Collections.singletonList(h))) {
      hoisted.add(h);
    }
  }
  List<JsName> hoistedNames=hoistedNameVisitor.getHoistedNames();
  if (!sawReturnStatement) {
    hoisted.add(new JsNameRef(x.getSourceInfo(),JsRootScope.INSTANCE.getUndefined()));
  }
  assert(hoisted.size() > 0);
  SourceInfo sourceInfo=x.getSourceInfo();
  ListIterator<JsExpression> i=hoisted.listIterator(hoisted.size());
  JsExpression op=i.previous();
  while (i.hasPrevious()) {
    JsBinaryOperation outerOp=new JsBinaryOperation(sourceInfo,JsBinaryOperator.COMMA);
    outerOp.setArg1(i.previous());
    outerOp.setArg2(op);
    op=outerOp;
  }
  if (!isInlinable(callerFunction,invokedFunction,thisExpr,x.getArguments(),op)) {
    return x;
  }
  NameRefReplacerVisitor v=new NameRefReplacerVisitor(thisExpr,x.getArguments(),invokedFunction.getParameters());
  for (ListIterator<JsName> nameIterator=hoistedNames.listIterator(); nameIterator.hasNext(); ) {
    JsName name=nameIterator.next();
    String ident;
    String base=invokedFunction.getName() + "String_Node_Str" + name.getIdent();
    JsScope scope=callerFunction.getScope();
    Multiset<String> startIdent=startIdentForScope.get(scope);
    if (startIdent == null) {
      startIdent=HashMultiset.create();
      startIdentForScope.put(scope,startIdent);
    }
    int suffix=startIdent.count(base);
    do {
      ident=base + "String_Node_Str" + suffix++;
    }
 while (scope.findExistingName(ident) != null);
    startIdent.setCount(base,suffix);
    JsName newName=scope.declareName(ident,name.getShortIdent());
    v.setReplacementName(name,newName);
    nameIterator.set(newName);
  }
  op=v.accept(op);
  op=(new CommaNormalizer(hoistedNames)).accept(op);
  if (invokedFunction.getInliningMode() != InliningMode.FORCE_INLINE && isTooComplexToInline(x,op) && isInvokedMoreThanOnce(invokedFunction)) {
    return x;
  }
  if (callerFunction == programFunction && hoistedNames.size() > 0) {
    return x;
  }
  newLocalVariableStack.peek().addAll(hoistedNames);
  invocationCountingVisitor.removeCountsFor(x);
  invocationCountingVisitor.accept(op);
  return op;
}

Fixed version (ground truth):
/** 
 * Determine if <code>invokedFunction</code> can be inlined into <code>callerFunction</code> at callsite <code>x</code>.
 * @return An expression equivalent to <code>x</code>
 */
private JsExpression process(JsInvocation x,JsFunction callerFunction,JsFunction invokedFunction){
  List<JsStatement> statements;
  if (invokedFunction.getBody() != null) {
    statements=Lists.newArrayList(invokedFunction.getBody().getStatements());
  }
 else {
    statements=Collections.emptyList();
  }
  List<JsExpression> hoisted=Lists.newArrayListWithCapacity(statements.size());
  JsExpression thisExpr=((JsNameRef)x.getQualifier()).getQualifier();
  HoistedNameVisitor hoistedNameVisitor=new HoistedNameVisitor(callerFunction.getScope(),invokedFunction.getScope());
  boolean sawReturnStatement=false;
  for (  JsStatement statement : statements) {
    if (sawReturnStatement) {
      return x;
    }
    JsExpression h=hoistedExpression(statement);
    if (h == null) {
      return x;
    }
    hoistedNameVisitor.accept(h);
    if (isReturnStatement(statement)) {
      sawReturnStatement=true;
      hoisted.add(h);
    }
 else     if (hasSideEffects(Collections.singletonList(h))) {
      hoisted.add(h);
    }
  }
  List<JsName> hoistedNames=hoistedNameVisitor.getHoistedNames();
  if (hoistedNames.size() != 0 && callerFunction == programFunction) {
    return x;
  }
  if (!sawReturnStatement) {
    hoisted.add(new JsNameRef(x.getSourceInfo(),JsRootScope.INSTANCE.getUndefined()));
  }
  assert(hoisted.size() > 0);
  SourceInfo sourceInfo=x.getSourceInfo();
  ListIterator<JsExpression> i=hoisted.listIterator(hoisted.size());
  JsExpression op=i.previous();
  while (i.hasPrevious()) {
    JsBinaryOperation outerOp=new JsBinaryOperation(sourceInfo,JsBinaryOperator.COMMA);
    outerOp.setArg1(i.previous());
    outerOp.setArg2(op);
    op=outerOp;
  }
  if (!isInlinable(callerFunction,invokedFunction,thisExpr,x.getArguments(),op)) {
    return x;
  }
  NameRefReplacerVisitor v=new NameRefReplacerVisitor(thisExpr,x.getArguments(),invokedFunction.getParameters());
  for (ListIterator<JsName> nameIterator=hoistedNames.listIterator(); nameIterator.hasNext(); ) {
    JsName name=nameIterator.next();
    String ident;
    String base=invokedFunction.getName() + "String_Node_Str" + name.getIdent();
    JsScope scope=callerFunction.getScope();
    Multiset<String> startIdent=startIdentForScope.get(scope);
    if (startIdent == null) {
      startIdent=HashMultiset.create();
      startIdentForScope.put(scope,startIdent);
    }
    int suffix=startIdent.count(base);
    do {
      ident=base + "String_Node_Str" + suffix++;
    }
 while (scope.findExistingName(ident) != null);
    startIdent.setCount(base,suffix);
    JsName newName=scope.declareName(ident,name.getShortIdent());
    v.setReplacementName(name,newName);
    nameIterator.set(newName);
  }
  op=v.accept(op);
  op=(new CommaNormalizer(hoistedNames)).accept(op);
  if (invokedFunction.getInliningMode() != InliningMode.FORCE_INLINE && isTooComplexToInline(x,op) && isInvokedMoreThanOnce(invokedFunction)) {
    return x;
  }
  if (callerFunction == programFunction && hoistedNames.size() > 0) {
    return x;
  }
  newLocalVariableStack.peek().addAll(hoistedNames);
  invocationCountingVisitor.removeCountsFor(x);
  invocationCountingVisitor.accept(op);
  return op;
}