Skip to content

8349847: Support configuring individual lint categories as errors #25558

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

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
63 changes: 22 additions & 41 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,50 +147,31 @@ protected Lint(Lint other) {

// Process command line options on demand to allow use of root Lint early during startup
private void initializeRootIfNeeded() {

// Already initialized?
if (values != null)
return;

// Initialize enabled categories based on "-Xlint" flags
if (options.isSet(Option.XLINT) || options.isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_ALL)) {
// If -Xlint or -Xlint:all is given, enable all categories by default
values = EnumSet.allOf(LintCategory.class);
} else if (options.isSet(Option.XLINT_CUSTOM, Option.LINT_CUSTOM_NONE)) {
// if -Xlint:none is given, disable all categories by default
values = LintCategory.newEmptySet();
} else {
// otherwise, enable on-by-default categories
values = LintCategory.newEmptySet();

Source source = Source.instance(context);
if (source.compareTo(Source.JDK9) >= 0) {
values.add(LintCategory.DEP_ANN);
}
if (Source.Feature.REDUNDANT_STRICTFP.allowedInSource(source)) {
values.add(LintCategory.STRICTFP);
}
values.add(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC);
values.add(LintCategory.OPENS);
values.add(LintCategory.MODULE);
values.add(LintCategory.REMOVAL);
if (!options.isSet(Option.PREVIEW)) {
values.add(LintCategory.PREVIEW);
}
values.add(LintCategory.IDENTITY);
values.add(LintCategory.INCUBATING);
if (values == null) {
values = options.getLintCategories(Option.XLINT, this::getDefaults);
suppressedValues = LintCategory.newEmptySet();
}
}

// Look for specific overrides
for (LintCategory lc : LintCategory.values()) {
if (options.isExplicitlyEnabled(Option.XLINT, lc)) {
values.add(lc);
} else if (options.isExplicitlyDisabled(Option.XLINT, lc)) {
values.remove(lc);
}
private EnumSet<LintCategory> getDefaults() {
Source source = Source.instance(context);
EnumSet<LintCategory> values = LintCategory.newEmptySet();
if (source.compareTo(Source.JDK9) >= 0) {
values.add(LintCategory.DEP_ANN);
}

suppressedValues = LintCategory.newEmptySet();
if (Source.Feature.REDUNDANT_STRICTFP.allowedInSource(source)) {
values.add(LintCategory.STRICTFP);
}
values.add(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC);
values.add(LintCategory.OPENS);
values.add(LintCategory.MODULE);
values.add(LintCategory.REMOVAL);
if (!options.isSet(Option.PREVIEW)) {
values.add(LintCategory.PREVIEW);
}
values.add(LintCategory.IDENTITY);
values.add(LintCategory.INCUBATING);
return values;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.nio.file.ReadOnlyFileSystemException;
import java.util.Collection;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -444,7 +445,8 @@ public JavaCompiler(Context context) {
context.get(DiagnosticListener.class) != null;
devVerbose = options.isSet("dev");
processPcks = options.isSet("process.packages");
werror = options.isSet(WERROR);
werrorAny = options.isSet(WERROR) || options.isSet(WERROR_CUSTOM, Option.LINT_CUSTOM_ALL);
werrorLint = options.getLintCategories(WERROR, LintCategory::newEmptySet);

verboseCompilePolicy = options.isSet("verboseCompilePolicy");

Expand Down Expand Up @@ -517,9 +519,13 @@ public boolean exists() {
*/
protected boolean processPcks;

/** Switch: treat warnings as errors
/** Switch: treat any kind of warning (including non-lint warnings) as an error.
*/
protected boolean werror;
protected boolean werrorAny;

/** Switch: treat lint warnings in the specified {@link LintCategory}s as errors.
*/
protected EnumSet<LintCategory> werrorLint;

/** Switch: is annotation processing requested explicitly via
* CompilationTask.setProcessors?
Expand Down Expand Up @@ -584,7 +590,8 @@ protected boolean shouldStop(CompileState cs) {
/** The number of errors reported so far.
*/
public int errorCount() {
if (werror && log.nerrors == 0 && log.nwarnings > 0) {
if (log.nerrors == 0 && log.nwarnings > 0 &&
(werrorAny || werrorLint.clone().removeAll(log.lintWarnings))) {
log.error(Errors.WarningsAndWerror);
}
return log.nerrors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ public void process(OptionHelper helper, String option) throws InvalidValueExcep
// treat warnings as errors
WERROR("-Werror", "opt.Werror", STANDARD, BASIC),

WERROR_CUSTOM("-Werror:", "opt.arg.Werror", "opt.Werror.custom", STANDARD, BASIC, ANYOF, getXLintChoices()),

// prompt after each error
// new Option("-prompt", "opt.prompt"),
PROMPT("-prompt", null, HIDDEN, BASIC),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ protected JavacProcessingEnvironment(Context context) {
}
fatalErrors = options.isSet("fatalEnterError");
showResolveErrors = options.isSet("showResolveErrors");
werror = options.isSet(Option.WERROR);
werror = options.isSet(Option.WERROR, PROCESSING, false);
fileManager = context.get(JavaFileManager.class);
platformAnnotations = initPlatformAnnotations();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,13 @@ javac.opt.source=\
Provide source compatibility with the specified Java SE release.\n\
Supported releases: \n {0}
javac.opt.Werror=\
Terminate compilation if warnings occur
Terminate compilation if any warnings occur
javac.opt.arg.Werror=\
<key>(,<key>)*
javac.opt.Werror.custom=\
Specify warnings that should terminate compilation, separated by comma.\n\
Precede a key by ''-'' to exclude the specified warning.\n\
Use --help-lint to see the supported keys.
javac.opt.A=\
Options to pass to annotation processors
javac.opt.implicit=\
Expand Down Expand Up @@ -330,9 +336,9 @@ javac.opt.X=\
javac.opt.help=\
Print this help message
javac.opt.help.lint=\
Print the supported keys for -Xlint
Print the supported keys for -Xlint and -Werror
javac.opt.help.lint.header=\
The supported keys for -Xlint are:
The supported keys for -Xlint and -Werror are:
javac.opt.print=\
Print out a textual representation of specified types
javac.opt.printRounds=\
Expand Down
30 changes: 25 additions & 5 deletions src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
Expand All @@ -41,6 +42,7 @@
import javax.tools.JavaFileObject;

import com.sun.tools.javac.api.DiagnosticFormatter;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.tree.EndPosTable;
Expand Down Expand Up @@ -403,10 +405,14 @@ protected int getDefaultMaxWarnings() {
*/
public int nerrors = 0;

/** The number of warnings encountered so far.
/** The total number of warnings encountered so far.
*/
public int nwarnings = 0;

/** Tracks whether any warnings have been encountered in each {@link LintCategory}.
*/
public final EnumSet<LintCategory> lintWarnings = LintCategory.newEmptySet();

/** The number of errors encountered after MaxErrors was reached.
*/
public int nsuppressederrors = 0;
Expand Down Expand Up @@ -671,7 +677,6 @@ protected void directError(String key, Object... args) {
*/
public void strictWarning(DiagnosticPosition pos, String key, Object ... args) {
writeDiagnostic(diags.warning(null, source, pos, key, args));
nwarnings++;
}

/**
Expand All @@ -689,6 +694,7 @@ public void report(JCDiagnostic diagnostic) {
public void clear() {
recorded.clear();
sourceMap.clear();
lintWarnings.clear();
nerrors = 0;
nwarnings = 0;
nsuppressederrors = 0;
Expand Down Expand Up @@ -730,7 +736,6 @@ public void report(JCDiagnostic diagnostic) {
if (emitWarnings || diagnostic.isMandatory()) {
if (nwarnings < MaxWarnings) {
writeDiagnostic(diagnostic);
nwarnings++;
} else {
nsuppressedwarns++;
}
Expand All @@ -742,7 +747,6 @@ public void report(JCDiagnostic diagnostic) {
shouldReport(diagnostic)) {
if (nerrors < MaxErrors) {
writeDiagnostic(diagnostic);
nerrors++;
} else {
nsuppressederrors++;
}
Expand All @@ -756,9 +760,25 @@ public void report(JCDiagnostic diagnostic) {
}

/**
* Write out a diagnostic.
* Write out a diagnostic and bump the warning and error counters as needed.
*/
protected void writeDiagnostic(JCDiagnostic diag) {

// Increment counter(s)
switch (diag.getType()) {
case WARNING:
nwarnings++;
Optional.of(diag)
.map(JCDiagnostic::getLintCategory)
.ifPresent(lintWarnings::add);
break;
case ERROR:
nerrors++;
break;
default:
break;
}

if (diagListener != null) {
diagListener.report(diag);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,54 @@ public boolean isExplicitlyDisabled(Option option, LintCategory lc) {
return !isSet(option, lc, true);
}

/**
* Collect the set of {@link LintCategory}s specified by option flag(s) of the form
* {@code -Flag} and/or {@code -Flag:[-]key,[-]key,...}.
*
* <p>
* The set of categories is calculated as folllows. First, an initial set is created:
* <ul>
* <li>If {@code -Flag} or {@code -Flag:all} appears, the initial set contains all categories; otherwise,
* <li>If {@code -Flag:none} appears, the initial set is empty; otherwise,
* <li>The {@code defaults} parameter is invoked to construct an initial set.
* </ul>
* Next, for each lint category key {@code key}:
* <ul>
* <li>If {@code -Flag:key} flag appears, the corresponding category is added to the set; otherwise
* <li>If {@code -Flag:-key} flag appears, the corresponding category is removed to the set
* </ul>
* Unrecognized {@code key}s are ignored.
*
* @param option the plain option
* @param defaults populates the default set, or null for an empty default set
* @return the specified set of categories
*/
public EnumSet<LintCategory> getLintCategories(Option option, Supplier<? extends EnumSet<LintCategory>> defaults) {

// Create the initial set
EnumSet<LintCategory> categories;
Option customOption = option.getCustom();
if (isSet(option) || isSet(customOption, Option.LINT_CUSTOM_ALL)) {
categories = EnumSet.allOf(LintCategory.class);
} else if (isSet(customOption, Option.LINT_CUSTOM_NONE)) {
categories = EnumSet.noneOf(LintCategory.class);
} else {
categories = defaults.get();
}

// Apply specific overrides
for (LintCategory category : LintCategory.values()) {
if (isExplicitlyEnabled(option, category)) {
categories.add(category);
} else if (isExplicitlyDisabled(option, category)) {
categories.remove(category);
}
}

// Done
return categories;
}

public void put(String name, String value) {
values.put(name, value);
initialized = true;
Expand Down
9 changes: 7 additions & 2 deletions src/jdk.compiler/share/man/javac.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
# Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -448,7 +448,12 @@ file system locations may be directories, JAR files or JMOD files.
: Prints version information.

<a id="option-Werror">`-Werror`</a>
: Terminates compilation when warnings occur.
: Terminates compilation when any warnings occur; this includes warnings in all lint
categories, as well as non-lint warnings.

<a id="option-Werror-custom">`-Werror:`\[`-`\]*key*(`,`\[`-`\]*key*)\*</a>
: Enables and/or disables specific categories of lint warnings that should terminate compilation.
See [`-Xlint`](#option-Xlint-custom) below for the list of lint category keys.

### Extra Options

Expand Down
4 changes: 4 additions & 0 deletions test/langtools/tools/javac/warnings/WerrorLint.e1.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
WerrorLint.java:20:19: compiler.warn.strictfp
- compiler.err.warnings.and.werror
1 error
1 warning
5 changes: 5 additions & 0 deletions test/langtools/tools/javac/warnings/WerrorLint.e2.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
WerrorLint.java:20:19: compiler.warn.strictfp
WerrorLint.java:21:30: compiler.warn.empty.if
- compiler.err.warnings.and.werror
1 error
2 warnings
23 changes: 23 additions & 0 deletions test/langtools/tools/javac/warnings/WerrorLint.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* @test /nodynamiccopyright/
* @bug 8349847
*
* @compile -XDrawDiagnostics -Xlint:none WerrorLint.java
* @compile -XDrawDiagnostics -Xlint:none -Werror WerrorLint.java
* @compile -XDrawDiagnostics -Xlint:none -Werror:empty WerrorLint.java
* @compile -XDrawDiagnostics -Xlint:none -Werror:strictfp WerrorLint.java
* @compile/ref=WerrorLint.w2.out -XDrawDiagnostics -Xlint:all WerrorLint.java
* @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror WerrorLint.java
* @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror:empty WerrorLint.java
* @compile/fail/ref=WerrorLint.e2.out -XDrawDiagnostics -Xlint:all -Werror:strictfp WerrorLint.java
* @compile/ref=WerrorLint.w1.out -XDrawDiagnostics WerrorLint.java
* @compile/fail/ref=WerrorLint.e1.out -XDrawDiagnostics -Werror WerrorLint.java
* @compile/ref=WerrorLint.w1.out -XDrawDiagnostics -Werror:empty WerrorLint.java
* @compile/fail/ref=WerrorLint.e1.out -XDrawDiagnostics -Werror:strictfp WerrorLint.java
*/

class WerrorLint {
strictfp void m() { // [strictfp] - this category is enabled by default
if (hashCode() == 1) ; // [empty] - this category is disabled by default
}
}
2 changes: 2 additions & 0 deletions test/langtools/tools/javac/warnings/WerrorLint.w1.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
WerrorLint.java:20:19: compiler.warn.strictfp
1 warning
3 changes: 3 additions & 0 deletions test/langtools/tools/javac/warnings/WerrorLint.w2.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
WerrorLint.java:20:19: compiler.warn.strictfp
WerrorLint.java:21:30: compiler.warn.empty.if
2 warnings