-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
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.
log.warning(LintCategory.SERIAL, | ||
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
@@ -529,6 +525,6 @@ synchronized void newOutputToPath(Path path) throws IOException { | |||
|
|||
// 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.
@@ -4470,9 +4469,9 @@ public void visitSelect(JCFieldAccess tree) { | |||
// If the qualified item is not a type and the selected item is static, report | |||
// 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.
}); | ||
} | ||
} | ||
|
||
void checkModuleRequires(final DiagnosticPosition pos, final RequiresDirective rd) { | ||
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
@@ -4294,13 +4256,12 @@ private boolean isCanonical(JCTree tree) { | |||
/** Check that an auxiliary class is not accessed from any other file than its own. | |||
*/ | |||
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
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 theTRY
lint, 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.
@@ -3002,7 +2968,7 @@ void checkAccessFromSerializableElement(final JCTree tree, boolean isLambda) { | |||
isEffectivelyNonPublic(sym)) { | |||
if (isLambda) { | |||
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.
public Warning(String prefix, String key, Object... args) { | ||
super(DiagnosticType.WARNING, prefix, key, args); | ||
} | ||
} | ||
|
||
/** | ||
* 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
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 |
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
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:
isEnabled
checklog::warning
call must share the sameLintCategory
Warnings
class must also make sense for the selectedLintCategory
This 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.properties
file;LintWarning
class is added toJCDiagnostic
to model a warning key that is also associated with a speicficLintCategory
enum constant;CompilerProperties
class has a new group of compiler keys, nested in the newLintWarnings
class. This class defines theLintWarning
objects for all the warning keys incompiler.properties
that have a lint category setLint::logIfEnabled(Position, LintWarning)
is added - which simplifies the logging of lint warnings in many common cases, by merging theisEnabled
check together with the logging.As bonus points, the signatures of some methods in
Check
andMandatoryWarningHandler
have been tightened to accept not just aWarning
, but aLintWarning
. This makes it impossible, for instance, to useCheck::warnUnchecked
with a warning that is not a true lint warning.Many thanks @archiecobbs for the useful discussions!
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/22553/head:pull/22553
$ git checkout pull/22553
Update a local copy of the PR:
$ git checkout pull/22553
$ git pull https://git.openjdk.org/jdk.git pull/22553/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 22553
View PR using the GUI difftool:
$ git pr show -t 22553
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/22553.diff
Using Webrev
Link to Webrev Comment