2019-04-12

Notes on bug JDK-8162455

I submitted bug JDK-8162455 some time ago (2016, so it says), and it's not a very important bug, so I can reasonably expect its fixing to be at a very low priority. Nevertheless, I'd like to comment on it, especially as it seems my original report wasn't terribly clear.

What's the problem?

As the bug report describes, if you specify an annotation-processor option to the Java compiler, and you correctly provide the corresponding processor to the compiler, you can get still a warning of the form:

The following options were not recognized by any processor: a list including that option

…if a certain part of the processor is never invoked (because none of the annotations it recognizes are present in the source). You also get it if you fail to specify the processor correctly (e.g., you get the classpath or the class's name wrong, or specify the service incorrectly, etc), so it's useful there. And you get it if you spell the option wrongly, so that's useful too. The problem is that either:

  • the logic that determines which options are to be reported is faulty, or
  • the message is faulty.

Which fault applies depends on what the intent of the warning is.

What's the intent?

The class com.sun.tools.javac.processing.JavacProcessingEnvironment implements this behaviour. It creates a set of the names of all provided options before annotation processing properly begins. Then, during that processing, it selectively removes entries matching those recognized by processors that it has just called to process a round. When all processing is complete, it generates the warning if the set is not empty.

Assuming its implementation accurately expresses its intent, a more accurate message would be:

The following options were not recognized by any engaged processor: options

…where engaged means having a processing round submitted to it.

But what use is knowing the options of an unengaged processor? If a processor had not been engaged, all of its options would be reported this way, so you're never going to be told about some of its options but not others (unless another processor was engaged, and unusually happened to use some of the same options). If this isn't the real intent, the logic must be faulty.

What if the intent is to inform about unengaged processors?:

  • Why not simply identify the processors directly?
  • If the options of an unengaged processor are also all recognized by an engaged processor, you won't be informed of the unengaged processor.
  • If an unengaged processor has no options, again you won't be informed.

The current logic doesn't robustly achieve this intent either. I have to presume that the message already expresses the intent.

What's the solution?

How should the logic be fixed? In JavacProcessingEnvironment, don't bother gradually eating away at the set of option names each time a processor is engaged. Instead, just before you check whether the set is empty at the end, go through all processors, and remove the options they support. The remainder is the set to report. A private method checks the set of remaining options, and reports if non-empty. You just have to eliminate the recognized ones before checking:

private void warnIfUnmatchedOptions() {
    for (ProcessorState ps : discoveredProcs)
        ps.removeSupportedOptions(unmatchedProcessorOptions);
    if (!unmatchedProcessorOptions.isEmpty())
        ...
}

So, although it's a fairly inconsequential bug, the fix is also pretty trivial, assuming that the iteration over the processors changes no other state, and that the intent is as I've presumed.