javac diagnostics

In recent releases, a lot of effort has been put into improving the diagnostics generated by javac. Partly, this has led to the evolution of the internal APIs used to generate diagnostics, but there is also some infrastructure outside of javac that is used to manage the set of diagnostic messages.

Diagnostic APIs

The primary reporting API is Log but these days this is just a facade for creating JCDiagnostic objects which are rendered by an instance of a DiagnosticFormatter. (All these classes are in com.sun.tools.javac.util.) Log also provides support for filtering and deferring diagnostics.

Diagnostics are composed of a message key and zero or more arguments. In general, the arguments are provided with their "natural" type, and are not converted to anything like String beforehand. The formatters can use the types of the arguments to decide how best to present the value. (For example, an IDE-based formatter could link the name of a symbol to its declaration.)

Two standard formatters are provided.

-XDrawDiagnostics

To facilitate debugging and to isolate “golden-file” tests from changes in the text of message strings, the diagnostic formatters provide a "raw diagnostics mode", in which the message key and arguments are printed directly, instead of being converted to a user-friendly text message. Normally, raw diagnostics mode works in conjunction with the basic diagnostic formatter, since it is the original content of the diagnostic that is being tested, but it can be useful to use raw diagnostics mode with the rich diagnostic formatter as a way of testing the functionality of the formatter itself.

Resource Files

The message keys are mapped to strings using standard resource bundles. The source for these are properties files in com.sun.tools.javac.resources. There are two primary properties files: (In addition, there are Chinese and Japanese translations stored alongside the English versions.)

In the primary versions of the property files, many of the property definitions are immediately preceded by a stylized comment. These comments indicate the nature of any values that will be substituted into the property value when generating the text for a diagnostic. The comments are in stylised English (such as “list of type” or “string or message segment”). The comments are suggested by the MessageInfo test utility, in conjunction with a set of examples to exercise as many diagnostics as possible.

The properties files are compiled into equivalent class files as part of the build process.

CheckResourceKeys

The test program langtools/test/tools/javac/diags/CheckResourceKeys compares the message keys defined in the javac resource bundles with the strings defined in the javac class files, and uses heuristics to determine which messages are not defined (but should be) and which messages are defined (but need not be.)

MessageInfo

This utility runs a set of examples, and from the types of the arguments for each message key, it generates the stylized comments for the corresponding message keys. It does not directly modify the resource files (since they are source files under source code management, but it does generate suggestions which can easily be cut and pasted into the resource files.

langtools/test/tools/javac/diags/examples

The langtools/test/tools/javac/diags/examples directory contains a large, organized collection of examples designed to provide basic coverage of as many javac diagnostics as possible. The purpose is to make it easy to see diagnostic messages in context, instead of as raw strings in a resource file. This is useful when proof-reading messages, and it is useful for localization teams to see how messages may be used.

Each example is intended to be as simple as possible to demonstrate a specific diagnostic. It is a non-goal to demonstrate the diagnostic in the context of a realistic program; likewise, it is a non-goal to demonstrate all the ways in which a diagnostic may appear. Each example is represented by a single file or a directory of files in the main examples directory. The name of the file or directory is derived from the key of the primary diagnostic the example is designed to illustrate.

Each example uses stylized comments to identify the message keys of the diagnostics that the example illustrates, and may contain additional comments for simple metadata such as how to run the example. These comments are used by two related utilities, CheckExamples and RunExamples.

CheckExamples

This program runs each example to verify that it generates exactly the set of message keys that are declared in the metadata for each example, and it compares the overall set of message keys against the keys defined in the javac resource bundles, to identify any messages that do not have a corresponding example.

Unfortunately, not all messages are easy to generate, such as those for handling IO exceptions or other system resource issues. And some messages come from defensive checks that should not fail in practice. To accomodate such messages, there is an exclusion mechanism, optimistically called the “not yet” list. The file for this is examples.not-yet.txt.

RunExamples

This program runs the examples and generates a report showing the source code for each example, and the corresponding messages generated by javac.

These utilities can be compiled and run standalone, but they can also be run by jtreg as part of the langtools test suite. There is also a target in the langtools make/build.xml file called diags-examples to run RunExamples.