-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8345263: Make sure that lint categories are used correctly when logging lint warnings #22553
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8345263: Make sure that lint categories are used correctly when logging lint warnings #22553
Conversation
Initial stab at adding a new LintWarning info
Readded Lint kind to processing warnings
Add Lint::logIfEnabled
|
👋 Welcome back mcimadamore! A progress list of the required criteria for merging this PR into |
|
@mcimadamore This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be: You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 153 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
|
@mcimadamore The following labels will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command. |
| if (lint.isEnabled(LintCategory.STRICTFP)) { | ||
| log.warning(LintCategory.STRICTFP, | ||
| pos, Warnings.Strictfp); } | ||
| deferredLintHandler.report(_ -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: we can remove the lambda braces now. Also in a few other places below.
| TreeInfo.diagnosticPositionFor(svuid, tree), | ||
| log.warning( | ||
| TreeInfo.diagnosticPositionFor(svuid, tree), | ||
| Warnings.ImproperSVUID((Symbol)e)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be changed to LintWarnings.ImproperSVUID? There are several other similar examples in this class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I probably misclassified some of these warnings
| // Check whether we've already opened this file for output | ||
| if (!outputFilesWritten.add(realPath)) | ||
| log.warning(LintCategory.OUTPUT_FILE_CLASH, Warnings.OutputFileClash(path)); | ||
| log.warning(LintWarnings.OutputFileClash(path)); // @@@: shouldn't we check for suppression? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re: "shouldn't we check for suppression?": If -Xlint:-output-file-clash is in effect, then outputFilesWritten will be null and you'll never get here.
| // a warning. Make allowance for the class of an array type e.g. Object[].class) | ||
| if (!sym.owner.isAnonymous()) { | ||
| chk.warnStatic(tree, Warnings.StaticNotQualifiedByType(sym.kind.kindName(), sym.owner)); | ||
| chk.lint.logIfEnabled(tree, LintWarnings.StaticNotQualifiedByType(sym.kind.kindName(), sym.owner)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an odd one - the rest of Attr uses env.info.lint but if I do that here I get some NPE in some unrelated JVM test. I wonder how robust using two different lints is... but for now I'll keep compatibility with what we have.
| if ((rd.module.flags() & Flags.AUTOMATIC_MODULE) != 0) { | ||
| deferredLintHandler.report(_l -> { | ||
| deferredLintHandler.report(_ -> { | ||
| if (rd.isTransitive() && lint.isEnabled(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is a bit odd - the warning can be reported under two categories, so the code makes sure we don't report twice. This is deliberate I've checked with @lahodaj
| * Helper method. Log a lint warning if its lint category is enabled. | ||
| */ | ||
| public void logIfEnabled(DiagnosticPosition pos, LintWarning warning) { | ||
| if (isEnabled(warning.getLintCategory())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure about this method. On the one hand it makes clients simpler - but it does require Lint keeping track of a log. An alternative could be to add a method in AbstractLog, e.g.:
warningIfEnabled(DiagnosticPosition pos, Lint lint, LintWarning key)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
elsewhere, @archiecobbs suggested to maybe make log a parameter of the method. I like the simplicity of the suggestion, and I will go with it.
Webrevs
|
Simplify some lambda expressions Simplify Lint::logIfEnabled by accepting a log parameter
| void checkForBadAuxiliaryClassAccess(DiagnosticPosition pos, Env<AttrContext> env, ClassSymbol c) { | ||
| if (lint.isEnabled(Lint.LintCategory.AUXILIARYCLASS) && | ||
| (c.flags() & AUXILIARY) != 0 && | ||
| if ((c.flags() & AUXILIARY) != 0 && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, and on a few other places, the checks were ordered so that the potentially more expensive checks were done after the isEnabled check. Checking the exact places, I don't think delaying the check is terrible for the cases in this PR, but if we would like to be adding new lints, we probably need something that will avoid running the lint's code completely in a (semi-)automatic way. That could be part of a more generic 22088.
(Admittedly, on some places, the isEnabled check was last, after the more expensive checks. This is particularly the case for the TRY lint, where the checks might be considerable.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we probably need something that will avoid running the lint's code completely in a (semi-)automatic way. That could be part of a more generic 22088.
Agreed.
Slight comment hijack follows...
The unnecessary suppression warning proposal would create a natural answer for this, because there would be a new concept "active" along with "enabled": A category is active if it's enabled OR we are tracking unnecessary suppressions, the category is being suppressed at this point in the code, and so far that suppression is unnecessary (i.e., no warnings would have fired yet).
So linter code would want to check for "active" status (instead of "enabled" status) before doing a non-trivial calculation, which would end up looking like this:
if (lint.isActive(LintCategory.FOO) &&
complicatedCalculationA() &&
complicatedCalculationB()) {
lint.logIfEnabled(log, pos, LintWarnings.FooProblem);
}But perhaps then we should then consider lambda-ification, which would simplify this down to:
lint.check(log, pos, LintWarnings.FooProblem,
() -> complicatedCalculationA() && complicatedCalculationB());This could be your "(semi-)automatic" option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, and on a few other places, the checks were ordered so that the potentially more expensive checks were done after the
isEnabledcheck. Checking the exact places, I don't think delaying the check is terrible for the cases in this PR, but if we would like to be adding new lints, we probably need something that will avoid running the lint's code completely in a (semi-)automatic way. That could be part of a more generic 22088.(Admittedly, on some places, the
isEnabledcheck was last, after the more expensive checks. This is particularly the case for theTRYlint, where the checks might be considerable.)
I was aware of that. As you might notice, in some cases I preserved the original code structure - in other cases I've changed it when the preceding checks seemed O(1) -- I might have made some mistakes, but that was the spirit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But perhaps then we should then consider lambda-ification, which would simplify this down to:
lint.check(log, pos, LintWarnings.FooProblem, () -> complicatedCalculationA() && complicatedCalculationB());
I thought about this as well but found it a bit too convoluted for my liking. One might already argue that Lint::logIfEnabled is doing two things at once (check and log). Making it an open box where you check if the lint is enabled, you check some user provided condition, and if both are true then you log" seems a rather ad-hoc API to add :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I just think the problem of "you checked for A, but are logging a B" is not big enough to warrant an hammer like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be better, IMHO, is to investigate an automate way to e.g. enhance something like CheckExamples to automatically test for suppression of lint warnings. E.g. for each diagnostic example that refers to a lint warning, it would be great if we could run the example with -Xlint:-xyz (to test command-line suppression) and maybe to auto-decorate the whole thing with @SuppressWarnings("xyz") and try again (to test programmatic supression) -- where xyz is the lint category associated to the compiler key under test. While this is probably too big to tacked as part of this PR, I don't see why we couldn't automate part of this -- and this will ensure that any issue where suppression is not respected is identified early in the process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be better, IMHO, is to investigate an automate way to e.g. enhance something like CheckExamples to automatically test for suppression of lint warnings.
Indeed... and I've already got a precursor which could serve as a starting point for something like that. What's missing in the precursor is automatic verification that every lint warning is tested, since until this PR that was impractical. But with this PR we can now enumerate all the LintWarning's, so it would be easy to automatically verify we have complete coverage. Of course, we'd also have to add all the missing warnable code examples, which is not hard but somewhat tedious. Let me know if you are interested in putting something together, I'm happy to help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But with this PR we can now enumerate all the
LintWarning
Yes, this is indeed the part I like the most about this PR. I'm already using it to collect a bunch of stats on how many lint warnings we have, how many warnings by category, etc. - which is very useful to spot inconsistencies etc.
| if (belongsToRestrictedPackage(sym)) { | ||
| log.warning(LintCategory.SERIAL, tree.pos(), | ||
| log.warning(tree.pos(), | ||
| Warnings.AccessToMemberFromSerializableLambda(sym)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so this one won't be a lint warning anymore I guess
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I think this is another accidentally omitted conversion from Warnings to LintWarnings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, this is a bug in compiler.properties.
| } | ||
|
|
||
| /** | ||
| * Class representing warning diagnostic keys. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
representing lint warning ...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch
vicente-romero-oracle
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
really nice simplification and clean-up
|
/label -build |
|
@magicus |
vicente-romero-oracle
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lvgtm
lahodaj
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks sensible to me.
|
I'm ready to integrate. I have, however, a question. We also have other localized
Eyeballing, it seems that these files seem to also be correctly annotated. Should I do anything in particular here? |
I assume you mean the So, I would expect that there should be nothing to do? (And even if something was needed, we usually do not modify the language-specific property files.) Do I miss something? |
Our build process should not depend on that right. However I noted that these files do contain annotations already. Whose job it is to update those? |
To reply to my own question, it seems these properties are bulk-updated at the end of the release cycle. Here's the one for 24: So, this PR doesn't need to do anything there. Thanks! |
|
/integrate |
|
Going to push as commit dbffe33.
Your commit was automatically rebased without conflicts. |
|
@mcimadamore Pushed as commit dbffe33. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
This PR tightens up the logic by which javac reports lint warnings. Currently, lint warnings are typically emitted using the following idiom:
There are some issues with this approach:
isEnabledchecklog::warningcall must share the sameLintCategoryWarningsclass must also make sense for the selectedLintCategoryThis PR addresses these issues, so that the above code is now written as follows:
The new idiom builds on a number of small improvements:
compiler.propertiesfile;LintWarningclass is added toJCDiagnosticto model a warning key that is also associated with a speicficLintCategoryenum constant;CompilerPropertiesclass has a new group of compiler keys, nested in the newLintWarningsclass. This class defines theLintWarningobjects for all the warning keys incompiler.propertiesthat have a lint category setLint::logIfEnabled(Position, LintWarning)is added - which simplifies the logging of lint warnings in many common cases, by merging theisEnabledcheck together with the logging.As bonus points, the signatures of some methods in
CheckandMandatoryWarningHandlerhave been tightened to accept not just aWarning, but aLintWarning. This makes it impossible, for instance, to useCheck::warnUncheckedwith a warning that is not a true lint warning.Many thanks @archiecobbs for the useful discussions!
Progress
Issue
Reviewers
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/22553/head:pull/22553$ git checkout pull/22553Update a local copy of the PR:
$ git checkout pull/22553$ git pull https://git.openjdk.org/jdk.git pull/22553/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 22553View PR using the GUI difftool:
$ git pr show -t 22553Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/22553.diff
Using Webrev
Link to Webrev Comment