Program: 28128
Project: 28128
Buggy source:
/** 
 * FunctionType := 'function' FunctionSignatureType FunctionSignatureType := TypeParameters '(' 'this' ':' TypeName, ParametersType ')' ResultType
 */
private Node parseFunctionType(JsDocToken token){
  if (token != JsDocToken.LP) {
    return reportTypeSyntaxWarning("String_Node_Str");
  }
  Node functionType=newNode(Token.FUNCTION);
  Node parameters=null;
  skipEOLs();
  if (!match(JsDocToken.RP)) {
    token=next();
    boolean hasParams=true;
    if (token == JsDocToken.STRING) {
      String tokenStr=stream.getString();
      boolean isThis="String_Node_Str".equals(tokenStr);
      boolean isNew="String_Node_Str".equals(tokenStr);
      if (isThis || isNew) {
        if (match(JsDocToken.COLON)) {
          next();
          skipEOLs();
          Node contextType=wrapNode(isThis ? Token.THIS : Token.NEW,parseTypeName(next()));
          if (contextType == null) {
            return null;
          }
          functionType.addChildToFront(contextType);
        }
 else {
          return reportTypeSyntaxWarning("String_Node_Str");
        }
        if (match(JsDocToken.COMMA)) {
          next();
          skipEOLs();
          token=next();
        }
 else {
          hasParams=false;
        }
      }
    }
    if (hasParams) {
      parameters=parseParametersType(token);
      if (parameters == null) {
        return null;
      }
    }
  }
  if (parameters != null) {
    functionType.addChildToBack(parameters);
  }
  skipEOLs();
  if (!match(JsDocToken.RP)) {
    return reportTypeSyntaxWarning("String_Node_Str");
  }
  skipEOLs();
  Node resultType=parseResultType(next());
  if (resultType == null) {
    return null;
  }
 else {
    functionType.addChildToBack(resultType);
  }
  return functionType;
}

Fixed version (ground truth):
/** 
 * FunctionType := 'function' FunctionSignatureType FunctionSignatureType := TypeParameters '(' 'this' ':' TypeName, ParametersType ')' ResultType
 */
private Node parseFunctionType(JsDocToken token){
  if (token != JsDocToken.LP) {
    restoreLookAhead(token);
    return reportTypeSyntaxWarning("String_Node_Str");
  }
  Node functionType=newNode(Token.FUNCTION);
  Node parameters=null;
  skipEOLs();
  if (!match(JsDocToken.RP)) {
    token=next();
    boolean hasParams=true;
    if (token == JsDocToken.STRING) {
      String tokenStr=stream.getString();
      boolean isThis="String_Node_Str".equals(tokenStr);
      boolean isNew="String_Node_Str".equals(tokenStr);
      if (isThis || isNew) {
        if (match(JsDocToken.COLON)) {
          next();
          skipEOLs();
          Node contextType=wrapNode(isThis ? Token.THIS : Token.NEW,parseTypeName(next()));
          if (contextType == null) {
            return null;
          }
          functionType.addChildToFront(contextType);
        }
 else {
          return reportTypeSyntaxWarning("String_Node_Str");
        }
        if (match(JsDocToken.COMMA)) {
          next();
          skipEOLs();
          token=next();
        }
 else {
          hasParams=false;
        }
      }
    }
    if (hasParams) {
      parameters=parseParametersType(token);
      if (parameters == null) {
        return null;
      }
    }
  }
  if (parameters != null) {
    functionType.addChildToBack(parameters);
  }
  skipEOLs();
  if (!match(JsDocToken.RP)) {
    return reportTypeSyntaxWarning("String_Node_Str");
  }
  skipEOLs();
  Node resultType=parseResultType(next());
  if (resultType == null) {
    return null;
  }
 else {
    functionType.addChildToBack(resultType);
  }
  return functionType;
}