Playing with formatters

In a recent work I started to change the shape of the output generated by javac - the changes I'm talking about are quite small (especially if compared to what the formatters are capable of); nonetheless, I think this could give you an idea of the direction in which we are headed. Let's start with a trivial example:

class Test {
    Integer m() {return "";}

When the program above is compiled with a standard javac, the following error message is generated: incompatible types
found   : java.lang.String
required: java.lang.Integer
    Integer m() {return "";}
1 error

Because of a recent change to javac, the same program now generates the following (slightly different) output: incompatible types
    Integer m() {return "";}
  required: java.lang.Integer
  found:    java.lang.String
1 error

As you can notice, the erroneous source line is now placed right after the first line of the error message - this makes it easier to figure out what went wrong, especially in situations where a given error message spans across multiple lines (like the one above). Another minor change is the the indentation of subsequent lines. Where's the magic - you might ask?

As I said in my earlier post about formatters, the biggest advantage that comes with diagnostic formatters is flexibility. We know well that it's almost impossible to come up with a format that will fit every single need; that's why each single piece of the above diagnostic can be customized, which means that now clients have the ability to decide how the compiler output should look like.

Javac output can be customized in many ways. A client can easily customize diagnostics coming out from the compiler by exploiting the new customisation functionalities provided by the Configuration object associated with the diagnostic formatter used by javac. The Configuration object provides several methods that can be leveraged in order to control a variety of things, e.g. which subparts of a diagnostic should be hidden (or shown), the amount of indentation to be assigned to each diagnostic element, etc.

Another way to change javac output is to exploit a bunch of hidden (and unsupported) options I've just added to the compiler in order to make it easy for us to experiment new layouts for javac diagnostics. We plan to support (part of) them via a more focussed set of supported options, once we have determined which controls are most useful.

The layout of a compiler diagnostic is made up of four different pieces:
  • summary - with the word summary we refer to the very first line of the diagnostic
  • details - the details of a diagnostic are the lines trailing the summary
  • subdiagnostics - A compiler diagnostic could be made up of sub-diagnostics (each one with its own summary, details and subdiagnostics!)
  • source line - the line of source code the diagnostic refers to

In the following example, different diagnostic subparts are rendered in different colours (red for the summary, purple for details and blue for the source line - for simplicity, no subdiagnostics are present): incompatible types
    Integer m() {return "";}
  required: java.lang.Integer
  found:    java.lang.String
1 error

In this example, the only indented part is details (the extra spaces before the source line were copied from the source code). The new formatters gives you the possibility of setting the preferred indentation value for each diagnostic subpart. For example, if you prefer old javac's diagnostics (I hope not!) you can easily get them by disabling indentation for all subparts and also by moving the source line at the bottom of the diagnostic (there are curently two supported positions for the source line, bottom and top; top is the default choice - it causes the source line to be moved after the summary line).

In order to achieve this from the command line you should specify both -XDdiagIndentation=0|0|0|0 (each integer value is the indentation level associated to a specific diagnostic subpart, in this case 0 for disabling indentation completely) and -XDsourcePosition=bottom (which moves the source line at the bottom of the diagnostic, as opposed to top).

Another important thing that a client might want to control is the verbosity level of diagnostics that come out of javac. Thanks to the Configuration object it is now possible to enable/disable any single subpart of a given diagnostic. For example, if a client needs compact diagnostics, it can enable just the summary and the source line, while hiding the remaining subparts, so that the following diagnostic will be generated: incompatible types
    Integer m() {return "";}
1 error

The current support for customising verbosity level from the command line is rather limited; you can use the -XDdiags=<flags>, where <flags> denote a list of comma-separated flags. Currently the compiler supports only two flags: short (for disabling all subparts but summary and source line) and [+,-]source (for enabling/disabling the source line - note that the source line is not displayed by default when the compiler generates raw output with the -XDrawDiagnostics flag).

Minor tunings are also available, such as the ability of enabling/disabling the caret that underlines the source line (hidden option: -XDshowCaret=[true|false]) and to control the amount of output associated to multiline diagnostics (I'll cover them in another entry!).

As you can see there's plenty of stuff to play with - all you need is to build the latest bits of the compiler (available here) and have fun!

As usual, thanks to Jon for all the valuable feedback and support


Clang (LMVV) is doing a great job: I like the underlines...

Posted by Christian Ullenboom on June 05, 2010 at 02:45 AM BST #

Post a Comment:
  • HTML Syntax: NOT allowed

Maurizio Cimadamore is a member of the langtools team based in Santa Clara, CA. His efforts are mainly focused on the type-system area of the Java compiler.


« April 2014