JDK-8348611 : Eliminate DeferredLintHandler and emit warnings after attribution
  • Type: Enhancement
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 25
  • Priority: P5
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2025-01-24
  • Updated: 2025-08-26
  • Resolved: 2025-08-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 26
26 b12Fixed
Related Reports
Relates :  
Description
In javac, lint warnings are generated by many parts of the compiler. Some of these parts execute before attribution and therefore require the services of the DeferredLintHandler so that @SuppressWarnings is handled properly. But there are some issues with this design and it could be cleaned up.

Quoting Maurizio (from https://github.com/openjdk/jdk/pull/23281)

<quote>
* The class seems to be serving too many masters -- the "immediate" mode seems to be a sign of that
* Using this class correctly is rather finicky, and depends on which part of javac you are on. For instance, Flow doesn't use it, because it is after Attr... in other words, reporting of lint warnings is not centralized - and each component does what it needs to get the job done -- understandable, but leads to messy code (this also leads to Check::setLint)
* The synergy between Lint and DeferredLintHandler goes quite deep. For instance, flush has to be called in a place where Lint has been augmented with the contents of the relevant SuppressWarnings. All these dependencies make it quite hard to verify that the code does what it needs to do.

My general feeling here is that we'd be better off with a separate compilation step that runs after all the various front-end steps (e.g. after Flow). E.g. up to Flow, we keep accumulating lint warnings grouped by declaration. Then, in a single pass we take care of updating Lint with the correct @SuppressWarning found in a given declaration, and flush all the pending lint warnings for all that declaration. This would also mean that Attr and Check would be hypothetically be freed from Lint duties.
</quote>

The following refactoring was proposed along those lines:

* Move the deferral logic of DeferredLintManager into Lint; the DeferredLintManager singleton goes away.
* Lint has a single flush() method which is invoked once per source file during the compiler warn() step (added by JDK-8344148)
    * First, lexical deferrals are remapped to innermost containing JCTree
    * Next, all warnings are emitted (in lexical order) by scanning the JCCompilationUnit and flushing each declaration
* Lint warnings are created via Lint.logIfEnabled() (or similar) at any time during compilation
    * If you can locate the warning with a JCTree, you supply that
    * Otherwise, you locate the warning with an integer pos source file offset
    * In either case, an assertion verifies that flush() has not yet been invoked
* No more need for "immediate mode"

Etc.

Comments
Changeset: 3e60ab51 Branch: master Author: Archie Cobbs <acobbs@openjdk.org> Date: 2025-08-20 15:04:48 +0000 URL: https://git.openjdk.org/jdk/commit/3e60ab51fea17098d852931a06f4f5a827ae0e78
20-08-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/24584 Date: 2025-04-10 20:23:15 +0000
03-07-2025