File: src/com/google/javascript/jscomp/LightweightMessageFormatter.java
Issue: Column-indicating caret is sometimes not in error output
For some reason, the caret doesn't always show up in the output when there are errors.

When test.js looks like this:

>alert(1;

, the output is this:

>java -jar compiler.jar --js test.js
test.js:1: ERROR - Parse error. missing ) after argument list

1 error(s), 0 warning(s)

However, when test.js looks like this (notice the line break after the semicolon):

>alert(1;
>

, the output is this:

>java -jar compiler.jar --js test.js
test.js:1: ERROR - Parse error. missing ) after argument list
alert(1;
        ^

1 error(s), 0 warning(s)

That's the simplest reproduction of the problem that I could come up with, but I just encountered the problem in a file with ~100 LOC in it. This is the first time I believe I've run into the problem, but when it happens, my error parser fails and it becomes a pain to track down the raw output to find the actual problem.

Tested against r1171, committed 6/10 08:06. The problem is present going back to at least r1000, so this isn't a new issue.

Buggy code:
private String format(JSError error, boolean warning) {
  // extract source excerpt
  SourceExcerptProvider source = getSource();
  String sourceExcerpt = source == null ? null :
      excerpt.get(
          source, error.sourceName, error.lineNumber, excerptFormatter);

  // formatting the message
  StringBuilder b = new StringBuilder();
  if (error.sourceName != null) {
    b.append(error.sourceName);
    if (error.lineNumber > 0) {
      b.append(':');
      b.append(error.lineNumber);
    }
    b.append(": ");
  }

  b.append(getLevelName(warning ? CheckLevel.WARNING : CheckLevel.ERROR));
  b.append(" - ");

  b.append(error.description);
  b.append('\n');
  if (sourceExcerpt != null) {
    b.append(sourceExcerpt);
    b.append('\n');
    int charno = error.getCharno();

    // padding equal to the excerpt and arrow at the end
    // charno == sourceExpert.length() means something is missing
    // at the end of the line
    if (excerpt.equals(LINE)
        && 0 <= charno && charno < sourceExcerpt.length()) {
      for (int i = 0; i < charno; i++) {
        char c = sourceExcerpt.charAt(i);
        if (Character.isWhitespace(c)) {
          b.append(c);
        } else {
          b.append(' ');
        }
      }
      b.append("^\n");
    }
  }
  return b.toString();
}

Fixed code:
private String format(JSError error, boolean warning) {
  // extract source excerpt
  SourceExcerptProvider source = getSource();
  String sourceExcerpt = source == null ? null :
      excerpt.get(
          source, error.sourceName, error.lineNumber, excerptFormatter);

  // formatting the message
  StringBuilder b = new StringBuilder();
  if (error.sourceName != null) {
    b.append(error.sourceName);
    if (error.lineNumber > 0) {
      b.append(':');
      b.append(error.lineNumber);
    }
    b.append(": ");
  }

  b.append(getLevelName(warning ? CheckLevel.WARNING : CheckLevel.ERROR));
  b.append(" - ");

  b.append(error.description);
  b.append('\n');
  if (sourceExcerpt != null) {
    b.append(sourceExcerpt);
    b.append('\n');
    int charno = error.getCharno();

    // padding equal to the excerpt and arrow at the end
    // charno == sourceExpert.length() means something is missing
    // at the end of the line
    if (excerpt.equals(LINE)
        && 0 <= charno && charno <= sourceExcerpt.length()) {
      for (int i = 0; i < charno; i++) {
        char c = sourceExcerpt.charAt(i);
        if (Character.isWhitespace(c)) {
          b.append(c);
        } else {
          b.append(' ');
        }
      }
      b.append("^\n");
    }
  }
  return b.toString();
}