Skip to content

8349847: Support configuring individual lint categories as errors #23622

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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.getLintCategoriesOf(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.getLintCategoriesOf(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 (lint or non-lint) 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,12 +590,20 @@ 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;
}

/**
* Should warnings in the given lint category be treated as errors due to a {@code -Werror} flag?
*/
public boolean isWerror(LintCategory lc) {
return werrorAny || werrorLint.contains(lc);
}

protected final <T> Queue<T> stopIfError(CompileState cs, Queue<T> queue) {
return shouldStop(cs) ? new ListBuffer<T>() : queue;
}
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 = compiler.isWerror(PROCESSING);
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 @@ -172,55 +172,83 @@ public boolean isUnset(Option option, String value) {
}

/**
* Check whether the given lint category is explicitly enabled or disabled.
* Determine if a specific {@link LintCategory} is explicitly enabled via a custom
* option flag of the form {@code -Flag:key}.
*
* <p>
* If the category is neither enabled nor disabled, return the given default value.
* Note: It's possible the category was also explicitly disabled; this method does not check that.
*
* @param option the plain (non-custom) option
* @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT})
* @param lc the {@link LintCategory} in question
* @param defaultValue presumed default value
* @return true if {@code lc} would be included
* @return true if {@code lc} has been explicitly enabled
*/
public boolean isSet(Option option, LintCategory lc, boolean defaultValue) {
public boolean isExplicitlyEnabled(Option option, LintCategory lc) {
Option customOption = option.getCustom();
if (lc.optionList.stream().anyMatch(alias -> isSet(customOption, alias))) {
return true;
}
if (lc.optionList.stream().anyMatch(alias -> isSet(customOption, "-" + alias))) {
return false;
}
if (isSet(option) || isSet(customOption, Option.LINT_CUSTOM_ALL)) {
return true;
}
if (isSet(customOption, Option.LINT_CUSTOM_NONE)) {
return false;
}
return defaultValue;
return lc.optionList.stream().anyMatch(alias -> isSet(customOption, alias));
}

/**
* Determine if a specific {@link LintCategory} was explicitly enabled via a custom option flag
* of the form {@code -Flag:all} or {@code -Flag:key}.
* Determine if a specific {@link LintCategory} is explicitly disabled via a custom
* option flag of the form {@code -Flag:-key}.
*
* @param option the option
* <p>
* Note: It's possible the category was also explicitly enabled; this method does not check that.
*
* @param option the plain (non-custom) version of the option (e.g., {@link Option#XLINT})
* @param lc the {@link LintCategory} in question
* @return true if {@code lc} has been explicitly enabled
* @return true if {@code lc} has been explicitly disabled
*/
public boolean isExplicitlyEnabled(Option option, LintCategory lc) {
return isSet(option, lc, false);
public boolean isExplicitlyDisabled(Option option, LintCategory lc) {
Option customOption = option.getCustom();
return lc.optionList.stream().anyMatch(alias -> isSet(customOption, "-" + alias));
}

/**
* Determine if a specific {@link LintCategory} was explicitly disabled via a custom option flag
* of the form {@code -Flag:none} or {@code -Flag:-key}.
* Collect the set of {@link LintCategory}s specified by option flag(s) of the form
* {@code -Flag} and/or {@code -Flag:[-]key,[-]key,...}.
*
* @param option the option
* @param lc the {@link LintCategory} in question
* @return true if {@code lc} has been explicitly disabled
* <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 boolean isExplicitlyDisabled(Option option, LintCategory lc) {
return !isSet(option, lc, true);
public EnumSet<LintCategory> getLintCategoriesOf(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) {
Expand Down
Loading