Skip to content
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

8224228: No way to locally suppress lint warnings in parser/tokenizer or preview features #23237

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Changes from 3 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8557999
Some cleanups relating to MandatoryWarningHandler.
archiecobbs Jan 16, 2025
224bd43
Refactor DeferredLintHandler to handle warnings generated during pars…
archiecobbs Jan 19, 2025
e4ef8f0
Merge branch 'master' into JDK-8224228
archiecobbs Jan 19, 2025
d1d16d8
Bug fixes.
archiecobbs Jan 21, 2025
3a0ac64
Merge branch 'master' into JDK-8224228
archiecobbs Jan 22, 2025
2509771
Fixes and cleanups.
archiecobbs Jan 22, 2025
9f1c259
Update DeferredLintHandler API to use JCTree instead of DiagnosticPos…
archiecobbs Jan 23, 2025
893fef8
Add Javadoc to document a subtley in the API.
archiecobbs Jan 23, 2025
405f3a4
Refactor the DeferredLintHandler API to maintain the "stack" itself.
archiecobbs Jan 23, 2025
7adada7
Merge branch 'JDK-8348427' into JDK-8224228
archiecobbs Jan 23, 2025
877b16c
Remove Attr.flushDeferredLintHandler() which doesn't appear necessary.
archiecobbs Jan 23, 2025
cecb228
Put back required flushing of binding pattern variable declaration.
archiecobbs Jan 23, 2025
0ce44d6
Merge branch 'master' into JDK-8347958 to fix conflict.
archiecobbs Jan 25, 2025
03f08d9
Merge branch 'master' into JDK-8224228 to fix conflict.
archiecobbs Jan 26, 2025
6cc1eae
Merge branch 'JDK-8347958' into JDK-8224228
archiecobbs Jan 26, 2025
7ad56bb
Instead of using EndPosTable, track ending positions of declarations …
archiecobbs Jan 28, 2025
40872df
Refactor to eliminate the unnecessary MandatoryWarningHandler "verbos…
archiecobbs Jan 29, 2025
73a5e88
Fix bugs when mapping lexical deferrals to declarations.
archiecobbs Jan 29, 2025
ebb6544
Refactor "dangling-doc-comments" logic to utilize new DeferredLintHan…
archiecobbs Jan 29, 2025
11b43d4
Fix an inaccurate comment.
archiecobbs Jan 30, 2025
35f99ff
Refactor to remove the "log" parameter from Lint.logIfEnabled().
archiecobbs Jan 31, 2025
376c418
Merge branch 'JDK-8349155' into JDK-8224228
archiecobbs Jan 31, 2025
44f5bed
Revert gratuituous whitespace change.
archiecobbs Jan 31, 2025
e83c88c
Merge branch 'master' into JDK-8224228
archiecobbs Feb 6, 2025
615d014
Merge branch 'master' into JDK-8224228 to fix conflicts.
archiecobbs Feb 12, 2025
6557782
Update copyright dates.
archiecobbs Feb 12, 2025
4fcc612
Track source end positions of declarations that support @SuppressWarn…
archiecobbs Feb 18, 2025
e235228
Add end position for variables coming from variableDeclaratorId().
archiecobbs Feb 18, 2025
fcccaa3
Merge branch 'JDK-8350212' (end positions sub-task) into JDK-8224228.
archiecobbs Feb 18, 2025
8ac827c
Remove unneeded end position tracking.
archiecobbs Feb 18, 2025
de6f80c
Refactor MandatoryWarningHandler to support dynamic verbosity.
archiecobbs Feb 21, 2025
f1e2a59
Merge branch 'JDK-8350514' (split out as sub-task) into JDK-8224228.
archiecobbs Feb 21, 2025
1161e80
Refactor to map positions to declarations all within the parser.
archiecobbs Feb 28, 2025
45c2aac
Add node type assertion check to endDecl() per review suggestion.
archiecobbs Feb 28, 2025
12d8c73
Rejigger LexicalLintHandler so it runs in linear time; add unit test.
archiecobbs Feb 28, 2025
31ef44b
Fix inconsistent bracket styling.
archiecobbs Feb 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -290,7 +290,7 @@ int compareToRange(int minPos, int maxPos) {
private class LexicalDeferralMapper extends TreeScanner {

private JCTree[] declMap;
private int currentDeferral;
private int nextDeferral;

void mapLexicalDeferrals(JCCompilationUnit tree) {

@@ -300,7 +300,7 @@ void mapLexicalDeferrals(JCCompilationUnit tree) {

// Initialize our mapping table
declMap = new JCTree[parsingDeferrals.size()];
currentDeferral = 0;
nextDeferral = 0;

// Scan declarations and map lexical deferrals to them
try {
@@ -348,34 +348,39 @@ private <T extends JCTree> void scanDecl(T decl, Consumer<? super T> recursion)
int minPos = TreeInfo.getStartPos(decl);
int maxPos = TreeInfo.endPos(decl);

// Skip forward through lexical deferrals until we hit this declaration
while (true) {
// Find those lexical deferrals that overlap this declaration and map them
int numMatches = 0;
while (nextDeferral + numMatches < parsingDeferrals.size()) {

// We can stop scanning once we pass the last lexical deferral
if (currentDeferral >= parsingDeferrals.size()) {
throw new ShortCircuitException();
}
// Where is this declaration relative to the next lexical deferral?
Deferral deferral = parsingDeferrals.get(nextDeferral + numMatches);
int relativePosition = deferral.compareToRange(minPos, maxPos);

// Get the deferral currently under consideration
Deferral deferral = parsingDeferrals.get(currentDeferral);
// If it's before it, then this declaration overlaps nothing in the list. This only
// happens with the initial declarations; after that, declarations always stay ahead.
// Keep recursing forward through the source code.
if (relativePosition > 0) {
break;
}

// Is its position prior to this declaration?
int relativePosition = deferral.compareToRange(minPos, maxPos);
// If it's after it, advance through the deferral list until we catch up with it
if (relativePosition < 0) {
currentDeferral++; // already past it
Assert.check(numMatches == 0);
nextDeferral++;
continue;
}

// Is its position after this declaration?
if (relativePosition > 0) {
break; // stop for now; a subsequent declaration might match
}
// The deferral is contained within this declaration, so map it to the declaration,
// and continue doing so for all immediately following deferrals that also match.
// Note, this declaration may not be the innermost containing declaration; if not,
// the narrower declaration(s) that follow will overwrite and correct the mapping.
declMap[nextDeferral + numMatches] = decl;
numMatches++;
}

// Deferral's position is within this declaration - we should map it.
// Note this declaration may not be the innermost containing declaration,
// but if not, that's OK: the narrower declaration will follow and overwrite.
declMap[currentDeferral] = decl;
break;
// Have we mapped all of the lexical deferrals? If so don't bother going any further.
if (nextDeferral >= parsingDeferrals.size()) {
throw new ShortCircuitException();
}

// Recurse
Original file line number Diff line number Diff line change
@@ -110,7 +110,7 @@ protected Preview(Context context) {
source = Source.instance(context);
verbose = Lint.instance(context).isEnabled(LintCategory.PREVIEW);
deferredLintHandler = DeferredLintHandler.instance(context);
previewHandler = new MandatoryWarningHandler(log, source, verbose, true);
previewHandler = new MandatoryWarningHandler(log, source, true);
forcePreview = options.isSet("forcePreview");
majorVersionToSource = initMajorVersionToSourceMap();
}
@@ -196,10 +196,6 @@ public void warnPreview(Lint lint, DiagnosticPosition pos, Feature feature) {
Assert.check(isEnabled());
Assert.check(isPreview(feature));
markUsesPreview(pos);

// For preview warnings, even if a warning is suppressed by of @SuppressWarnings("preview"), we
// still need the "recompile" note at the end of compilation. To ensure that happens, we invoke
// previewHandler.report() in all cases, but with "verbose" set to false if "preview" is suppressed.
previewHandler.report(pos, feature.isPlural() ?
LintWarnings.PreviewFeatureUsePlural(feature.nameFragment()) :
LintWarnings.PreviewFeatureUse(feature.nameFragment()),
@@ -229,7 +225,7 @@ public void markUsesPreview(DiagnosticPosition pos) {
}

public void reportPreviewWarning(DiagnosticPosition pos, LintWarning warnKey) {
previewHandler.report(pos, warnKey);
previewHandler.report(pos, warnKey, verbose);
}

public boolean usesPreview(JavaFileObject file) {
21 changes: 10 additions & 11 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
Original file line number Diff line number Diff line change
@@ -162,14 +162,11 @@ protected Check(Context context) {
profile = Profile.instance(context);
preview = Preview.instance(context);

boolean verboseDeprecated = lint.isEnabled(LintCategory.DEPRECATION);
boolean verboseRemoval = lint.isEnabled(LintCategory.REMOVAL);
boolean verboseUnchecked = lint.isEnabled(LintCategory.UNCHECKED);
boolean enforceMandatoryWarnings = true;

deprecationHandler = new MandatoryWarningHandler(log, null, verboseDeprecated, enforceMandatoryWarnings, "deprecated");
removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval, enforceMandatoryWarnings);
uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked, enforceMandatoryWarnings);
deprecationHandler = new MandatoryWarningHandler(log, null, enforceMandatoryWarnings, "deprecated");
removalHandler = new MandatoryWarningHandler(log, null, enforceMandatoryWarnings);
uncheckedHandler = new MandatoryWarningHandler(log, null, enforceMandatoryWarnings);

deferredLintHandler = DeferredLintHandler.instance(context);

@@ -238,17 +235,19 @@ MethodSymbol setMethod(MethodSymbol newMethod) {
void warnDeprecated(DiagnosticPosition pos, Symbol sym) {
if (sym.isDeprecatedForRemoval()) {
if (!lint.isSuppressed(LintCategory.REMOVAL)) {
boolean verbose = lint.isEnabled(LintCategory.REMOVAL);
if (sym.kind == MDL) {
removalHandler.report(pos, LintWarnings.HasBeenDeprecatedForRemovalModule(sym));
removalHandler.report(pos, LintWarnings.HasBeenDeprecatedForRemovalModule(sym), verbose);
} else {
removalHandler.report(pos, LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location()));
removalHandler.report(pos, LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location()), verbose);
}
}
} else if (!lint.isSuppressed(LintCategory.DEPRECATION)) {
boolean verbose = lint.isEnabled(LintCategory.DEPRECATION);
if (sym.kind == MDL) {
deprecationHandler.report(pos, LintWarnings.HasBeenDeprecatedModule(sym));
deprecationHandler.report(pos, LintWarnings.HasBeenDeprecatedModule(sym), verbose);
} else {
deprecationHandler.report(pos, LintWarnings.HasBeenDeprecated(sym, sym.location()));
deprecationHandler.report(pos, LintWarnings.HasBeenDeprecated(sym, sym.location()), verbose);
}
}
}
@@ -285,7 +284,7 @@ public void warnRestrictedAPI(DiagnosticPosition pos, Symbol sym) {
*/
public void warnUnchecked(DiagnosticPosition pos, LintWarning warnKey) {
if (!lint.isSuppressed(LintCategory.UNCHECKED))
uncheckedHandler.report(pos, warnKey);
uncheckedHandler.report(pos, warnKey, lint.isEnabled(LintCategory.UNCHECKED));
}

/**
Original file line number Diff line number Diff line change
@@ -113,9 +113,6 @@ public class JavacParser implements Parser {
/** End position mappings container */
protected final AbstractEndPosTable endPosTable;

/** A map associating "other nearby documentation comments"
* with the preferred documentation comment for a declaration. */
protected Map<Comment, List<Comment>> danglingComments = new HashMap<>();
/** Handler for deferred diagnostics. */
protected final DeferredLintHandler deferredLintHandler;

@@ -582,17 +579,8 @@ protected void checkNoMods(int pos, long mods) {
* (using {@code token.getDocComment()}.
* 3. At the end of the "signature" of the declaration
* (that is, before any initialization or body for the
* declaration) any other "recent" comments are saved
* in a map using the primary comment as a key,
* using this method, {@code saveDanglingComments}.
* 4. When the tree node for the declaration is finally
* available, and the primary comment, if any,
* is "attached", (in {@link #attach}) any related
* dangling comments are also attached to the tree node
* by registering them using the {@link #deferredLintHandler}.
* 5. (Later) Warnings may be generated for the dangling
* comments, subject to the {@code -Xlint} and
* {@code @SuppressWarnings}.
* declaration) any other "recent" comments are
* reported to the {@link #deferredLintHandler}.
*
* @param dc the primary documentation comment
*/
@@ -612,21 +600,16 @@ private void saveDanglingDocComments(Comment dc) {
}
}

var lb = new ListBuffer<Comment>();
while (!recentComments.isEmpty()) {
var c = recentComments.remove();
if (c != dc) {
lb.add(c);
reportDanglingDocComment(c);
}
}
danglingComments.put(dc, lb.toList());
}

/** Make an entry into docComments hashtable,
* provided flag keepDocComments is set and given doc comment is non-null.
* If there are any related "dangling comments", register
* diagnostics to be handled later, when @SuppressWarnings
* can be taken into account.
*
* @param tree The tree to be used as index in the hashtable
* @param dc The doc comment to associate with the tree, or null.
@@ -635,26 +618,6 @@ protected void attach(JCTree tree, Comment dc) {
if (keepDocComments && dc != null) {
docComments.putComment(tree, dc);
}
reportDanglingComments(tree, dc);
}

/** Reports all dangling comments associated with the
* primary comment for a declaration against the position
* of the tree node for a declaration.
*
* @param tree the tree node for the declaration
* @param dc the primary comment for the declaration
*/
void reportDanglingComments(JCTree tree, Comment dc) {
var list = danglingComments.remove(dc);
if (list != null) {
deferredLintHandler.push(tree);
try {
list.forEach(this::reportDanglingDocComment);
} finally {
deferredLintHandler.pop();
}
}
}

/**
@@ -667,13 +630,16 @@ void reportDanglingComments(JCTree tree, Comment dc) {
void reportDanglingDocComment(Comment c) {
var pos = c.getPos();
if (pos != null) {
deferredLintHandler.report(lint -> {
if (lint.isEnabled(Lint.LintCategory.DANGLING_DOC_COMMENTS) &&
!shebang(c, pos)) {
log.warning(
pos, LintWarnings.DanglingDocComment);
}
});
deferredLintHandler.push(pos.getPreferredPosition());
try {
deferredLintHandler.report(lint -> {
if (lint.isEnabled(Lint.LintCategory.DANGLING_DOC_COMMENTS) && !shebang(c, pos)) {
log.warning(pos, LintWarnings.DanglingDocComment);
}
});
} finally {
deferredLintHandler.pop();
}
}
}

Original file line number Diff line number Diff line change
@@ -109,56 +109,36 @@ private enum DeferredDiagnosticKind {
*
* @param log The log on which to generate any diagnostics
* @param source Associated source file, or null for none
* @param verbose Specify whether or not detailed messages about
* individual instances should be given, or whether an aggregate
* message should be generated at the end of the compilation.
* Typically set via -Xlint:option.
* @param enforceMandatory
* True if mandatory warnings and notes are being enforced.
*/
public MandatoryWarningHandler(Log log, Source source, boolean verbose, boolean enforceMandatory) {
this(log, source, verbose, enforceMandatory, null);
public MandatoryWarningHandler(Log log, Source source, boolean enforceMandatory) {
this(log, source, enforceMandatory, null);
}

/**
* Create a handler for mandatory warnings.
*
* @param log The log on which to generate any diagnostics
* @param source Associated source file, or null for none
* @param verbose Specify whether or not detailed messages about
* individual instances should be given, or whether an aggregate
* message should be generated at the end of the compilation.
* Typically set via -Xlint:option.
* @param enforceMandatory
* True if mandatory warnings and notes are being enforced.
* @param prefix A common prefix for the set of message keys for the messages
* that may be generated, or null to infer from the lint category.
*/
public MandatoryWarningHandler(Log log, Source source, boolean verbose, boolean enforceMandatory, String prefix) {
public MandatoryWarningHandler(Log log, Source source, boolean enforceMandatory, String prefix) {
this.log = log;
this.source = source;
this.verbose = verbose;
this.prefix = prefix;
this.enforceMandatory = enforceMandatory;
}

/**
* Report a mandatory warning using the default "verbose" setting.
* Report a mandatory warning.
*
* @param pos source code position
* @param warnKey lint warning
*/
public void report(DiagnosticPosition pos, LintWarning warnKey) {
report(pos, warnKey, verbose);
}

/**
* Report a mandatory warning using the provided "verbose" setting.
*
* @param pos source code position
* @param warnKey lint warning
* @param verbose true to emit a distinct warning, false to trigger
* an aggregate message at the end of compilation
* @param verbose true to emit a distinct warning, false just to register a deferred message
*/
public void report(DiagnosticPosition pos, LintWarning warnKey, boolean verbose) {
JavaFileObject currentSource = log.currentSourceFile();
@@ -238,12 +218,6 @@ public void reportDeferredDiagnostic() {
private final Log log;
private final Source source;

/**
* Whether or not to report individual warnings, or simply to report a
* single aggregate warning at the end of the compilation.
*/
private final boolean verbose;

/**
* The common prefix for all I18N message keys generated by this handler.
*/