8359493: Refactor how aggregated mandatory warnings are handled in the compiler

8350514: Refactor MandatoryWarningHandler to support dynamic verbosity

Reviewed-by: mcimadamore
This commit is contained in:
Archie Cobbs 2025-07-03 18:13:07 +00:00
parent a2315ddd2a
commit 25ed36f3ef
16 changed files with 271 additions and 248 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -47,6 +47,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
@ -93,7 +94,9 @@ public class ClassGenerator {
FACTORY_FIELD_LINT("factory.decl.field.lint"),
WILDCARDS_EXTENDS("wildcards.extends"),
SUPPRESS_WARNINGS("suppress.warnings"),
LINT_CATEGORY("lint.category");
LINT_CATEGORY("lint.category"),
DIAGNOSTIC_FLAGS_EMPTY("diagnostic.flags.empty"),
DIAGNOSTIC_FLAGS_NON_EMPTY("diagnostic.flags.non-empty");
/** stub key (as it appears in the property file) */
String key;
@ -259,17 +262,30 @@ public class ClassGenerator {
.map(MessageLine::lintCategory)
.findFirst().orElse(null);
//System.out.println("category for " + key + " = " + lintCategory);
String diagnosticFlags = lines.stream()
.filter(MessageLine::isDiagnosticFlags)
.map(MessageLine::diagnosticFlags)
.flatMap(Stream::of)
.map(s -> s.replace('-', '_'))
.map(s -> s.toUpperCase(Locale.ROOT))
.collect(Collectors.joining(", "));
String factoryName = factoryName(key);
if (msgInfo.getTypes().isEmpty()) {
//generate field
String factoryField;
if (lintCategory == null) {
factoryField = StubKind.FACTORY_FIELD.format(k.keyClazz, factoryName,
diagnosticFlags.isEmpty() ?
StubKind.DIAGNOSTIC_FLAGS_EMPTY.format() :
StubKind.DIAGNOSTIC_FLAGS_NON_EMPTY.format(diagnosticFlags),
"\"" + keyParts[0] + "\"",
"\"" + Stream.of(keyParts).skip(2).collect(Collectors.joining(".")) + "\"",
javadoc);
} else {
factoryField = StubKind.FACTORY_FIELD_LINT.format(k.keyClazz, factoryName,
diagnosticFlags.isEmpty() ?
StubKind.DIAGNOSTIC_FLAGS_EMPTY.format() :
StubKind.DIAGNOSTIC_FLAGS_NON_EMPTY.format(diagnosticFlags),
StubKind.LINT_CATEGORY.format("\"" + lintCategory + "\""),
"\"" + keyParts[0] + "\"",
"\"" + Stream.of(keyParts).skip(2).collect(Collectors.joining(".")) + "\"",
@ -287,11 +303,17 @@ public class ClassGenerator {
String methodBody;
if (lintCategory == null) {
methodBody = StubKind.FACTORY_METHOD_BODY.format(k.keyClazz,
diagnosticFlags.isEmpty() ?
StubKind.DIAGNOSTIC_FLAGS_EMPTY.format() :
StubKind.DIAGNOSTIC_FLAGS_NON_EMPTY.format(diagnosticFlags),
"\"" + keyParts[0] + "\"",
"\"" + Stream.of(keyParts).skip(2).collect(Collectors.joining(".")) + "\"",
argNames.stream().collect(Collectors.joining(", ")));
} else {
methodBody = StubKind.FACTORY_METHOD_BODY_LINT.format(k.keyClazz,
diagnosticFlags.isEmpty() ?
StubKind.DIAGNOSTIC_FLAGS_EMPTY.format() :
StubKind.DIAGNOSTIC_FLAGS_NON_EMPTY.format(diagnosticFlags),
StubKind.LINT_CATEGORY.format("\"" + lintCategory + "\""),
"\"" + keyParts[0] + "\"",
"\"" + Stream.of(keyParts).skip(2).collect(Collectors.joining(".")) + "\"",

View File

@ -32,7 +32,8 @@ import java.util.List;
* A message within the message file.
* A message is a series of lines containing a "name=value" property,
* optionally preceded by a comment describing the use of placeholders
* such as {0}, {1}, etc within the property value.
* such as {0}, {1}, etc within the property value, a lint category,
* and/or a list of diagnostic flags.
*/
public final class Message {
final MessageLine firstLine;
@ -49,7 +50,7 @@ public final class Message {
public MessageInfo getMessageInfo() {
if (messageInfo == null) {
MessageLine l = firstLine.prev;
if (l != null && l.isLint()) {
while (l != null && (l.isLint() || l.isDiagnosticFlags())) {
l = l.prev;
}
if (l != null && l.isInfo())
@ -74,7 +75,7 @@ public final class Message {
while (l.text.isEmpty())
l = l.next;
} else {
if (l.prev != null && (l.prev.isInfo() || l.prev.isLint()))
while (l.prev != null && (l.prev.isInfo() || l.prev.isLint() || l.prev.isDiagnosticFlags()))
l = l.prev;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -25,6 +25,7 @@
package propertiesparser.parser;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -39,6 +40,7 @@ public class MessageLine {
static final Pattern infoPattern = Pattern.compile(String.format("# ([0-9]+: %s, )*[0-9]+: %s",
typePattern.pattern(), typePattern.pattern()));
static final Pattern lintPattern = Pattern.compile("# lint: ([a-z\\-]+)");
static final Pattern diagnosticFlagsPattern = Pattern.compile("# flags: ([a-z\\-]+(, ([a-z\\-]+))*)");
public String text;
MessageLine prev;
@ -69,6 +71,19 @@ public class MessageLine {
}
}
public boolean isDiagnosticFlags() {
return diagnosticFlagsPattern.matcher(text).matches();
}
public String[] diagnosticFlags() {
Matcher matcher = diagnosticFlagsPattern.matcher(text);
if (matcher.matches()) {
return matcher.group(1).split(", ", -1);
} else {
return null;
}
}
boolean hasContinuation() {
return (next != null) && text.endsWith("\\");
}

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2015, 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
@ -27,6 +27,7 @@ toplevel.decl=\
package {0};\n\
\n\
{1}\n\
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;\n\
import com.sun.tools.javac.util.JCDiagnostic.Error;\n\
import com.sun.tools.javac.util.JCDiagnostic.Warning;\n\
import com.sun.tools.javac.util.JCDiagnostic.LintWarning;\n\
@ -34,6 +35,10 @@ toplevel.decl=\
import com.sun.tools.javac.util.JCDiagnostic.Fragment;\n\
import com.sun.tools.javac.code.Lint.LintCategory;\n\
\n\
import java.util.EnumSet;\n\
\n\
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;\n\
\n\
public class {2} '{'\n\
{3}\n\
'}'\n
@ -58,22 +63,22 @@ factory.decl.method.arg=\
arg{0}
factory.decl.method.body=\
return new {0}({1}, {2}, {3});
return new {0}({1}, {2}, {3}, {4});
factory.decl.method.body.lint=\
return new {0}({1}, {2}, {3}, {4});
return new {0}({1}, {2}, {3}, {4}, {5});
factory.decl.field=\
/**\n\
' '* {4}\n\
' '*/\n\
public static final {0} {1} = new {0}({2}, {3});
public static final {0} {1} = new {0}({2}, {3}, {4});
factory.decl.field.lint=\
/**\n\
' '* {5}\n\
' '*/\n\
public static final {0} {1} = new {0}({2}, {3}, {4});
public static final {0} {1} = new {0}({2}, {3}, {4}, {5});
wildcards.extends=\
{0}<? extends {1}>
@ -84,3 +89,9 @@ suppress.warnings=\
lint.category=\
LintCategory.get({0}).get()
diagnostic.flags.empty=\
EnumSet.noneOf(DiagnosticFlag.class)
diagnostic.flags.non-empty=\
EnumSet.of({0})

View File

@ -272,8 +272,6 @@ public class JavacTaskPool {
((ReusableJavaCompiler)ReusableJavaCompiler.instance(this)).clear();
Types.instance(this).newRound();
Check.instance(this).newRound();
Check.instance(this).clear(); //clear mandatory warning handlers
Preview.instance(this).clear(); //clear mandatory warning handlers
Modules.instance(this).newRound();
Annotate.instance(this).newRound();
CompileStates.instance(this).clear();

View File

@ -40,7 +40,6 @@ import com.sun.tools.javac.util.JCDiagnostic.LintWarning;
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.Warning;
import com.sun.tools.javac.util.Log;
import com.sun.tools.javac.util.MandatoryWarningHandler;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Options;
@ -71,9 +70,6 @@ public class Preview {
/** flag: is the "preview" lint category enabled? */
private final boolean verbose;
/** the diag handler to manage preview feature usage diagnostics */
private final MandatoryWarningHandler previewHandler;
/** test flag: should all features be considered as preview features? */
private final boolean forcePreview;
@ -105,7 +101,6 @@ public class Preview {
log = Log.instance(context);
source = Source.instance(context);
verbose = Lint.instance(context).isEnabled(LintCategory.PREVIEW);
previewHandler = new MandatoryWarningHandler(log, source, verbose, true, LintCategory.PREVIEW);
forcePreview = options.isSet("forcePreview");
majorVersionToSource = initMajorVersionToSourceMap();
}
@ -176,7 +171,8 @@ public class Preview {
Assert.check(isEnabled());
Assert.check(isPreview(feature));
markUsesPreview(pos);
previewHandler.report(pos, feature.isPlural() ?
log.mandatoryWarning(pos,
feature.isPlural() ?
LintWarnings.PreviewFeatureUsePlural(feature.nameFragment()) :
LintWarnings.PreviewFeatureUse(feature.nameFragment()));
}
@ -203,10 +199,6 @@ public class Preview {
sourcesWithPreviewFeatures.add(log.currentSourceFile());
}
public void reportPreviewWarning(DiagnosticPosition pos, LintWarning warnKey) {
previewHandler.report(pos, warnKey);
}
public boolean usesPreview(JavaFileObject file) {
return sourcesWithPreviewFeatures.contains(file);
}
@ -269,25 +261,13 @@ public class Preview {
return false;
}
/**
* Report any deferred diagnostics.
*/
public void reportDeferredDiagnostics() {
previewHandler.reportDeferredDiagnostic();
}
public void clear() {
previewHandler.clear();
}
public void checkSourceLevel(DiagnosticPosition pos, Feature feature) {
if (isPreview(feature) && !isEnabled()) {
//preview feature without --preview flag, error
log.error(JCDiagnostic.DiagnosticFlag.SOURCE_LEVEL, pos, disabledError(feature));
log.error(pos, disabledError(feature));
} else {
if (!feature.allowedInSource(source)) {
log.error(JCDiagnostic.DiagnosticFlag.SOURCE_LEVEL, pos,
feature.error(source.name));
log.error(pos, feature.error(source.name));
}
if (isEnabled() && isPreview(feature)) {
warnPreview(pos, feature);

View File

@ -79,7 +79,6 @@ import static com.sun.tools.javac.code.Kinds.Kind.*;
import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.code.TypeTag.WILDCARD;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
/** This is the main context-dependent analysis phase in GJC. It
* encompasses name resolution, type checking and constant folding as
@ -4146,8 +4145,7 @@ public class Attr extends JCTree.Visitor {
!exprtype.isErroneous() && !clazztype.isErroneous() &&
tree.pattern.getTag() != RECORDPATTERN) {
if (!allowUnconditionalPatternsInstanceOf) {
log.error(DiagnosticFlag.SOURCE_LEVEL, tree.pos(),
Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF.error(this.sourceName));
log.error(tree.pos(), Feature.UNCONDITIONAL_PATTERN_IN_INSTANCEOF.error(this.sourceName));
}
}
typeTree = TreeInfo.primaryPatternTypeTree((JCPattern) tree.pattern);
@ -4167,8 +4165,7 @@ public class Attr extends JCTree.Visitor {
if (allowReifiableTypesInInstanceof) {
valid = checkCastablePattern(tree.expr.pos(), exprtype, clazztype);
} else {
log.error(DiagnosticFlag.SOURCE_LEVEL, tree.pos(),
Feature.REIFIABLE_TYPES_INSTANCEOF.error(this.sourceName));
log.error(tree.pos(), Feature.REIFIABLE_TYPES_INSTANCEOF.error(this.sourceName));
allowReifiableTypesInInstanceof = true;
}
if (!valid) {

View File

@ -164,18 +164,6 @@ public class Check {
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, LintCategory.DEPRECATION, "deprecated");
removalHandler = new MandatoryWarningHandler(log, null, verboseRemoval,
enforceMandatoryWarnings, LintCategory.REMOVAL);
uncheckedHandler = new MandatoryWarningHandler(log, null, verboseUnchecked,
enforceMandatoryWarnings, LintCategory.UNCHECKED);
deferredLintHandler = DeferredLintHandler.instance(context);
allowModules = Feature.MODULES.allowedInSource(source);
@ -192,18 +180,6 @@ public class Check {
*/
private Map<Pair<ModuleSymbol, Name>,ClassSymbol> compiled = new HashMap<>();
/** A handler for messages about deprecated usage.
*/
private MandatoryWarningHandler deprecationHandler;
/** A handler for messages about deprecated-for-removal usage.
*/
private MandatoryWarningHandler removalHandler;
/** A handler for messages about unchecked or unsafe usage.
*/
private MandatoryWarningHandler uncheckedHandler;
/** A handler for deferred lint warnings.
*/
private DeferredLintHandler deferredLintHandler;
@ -253,21 +229,24 @@ public class Check {
* @param sym The deprecated symbol.
*/
void warnDeprecated(DiagnosticPosition pos, Symbol sym) {
LintWarning warningKey = null;
if (sym.isDeprecatedForRemoval()) {
if (!lint.isSuppressed(LintCategory.REMOVAL)) {
if (sym.kind == MDL) {
removalHandler.report(pos, LintWarnings.HasBeenDeprecatedForRemovalModule(sym));
warningKey = LintWarnings.HasBeenDeprecatedForRemovalModule(sym);
} else {
removalHandler.report(pos, LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location()));
warningKey = LintWarnings.HasBeenDeprecatedForRemoval(sym, sym.location());
}
}
} else if (!lint.isSuppressed(LintCategory.DEPRECATION)) {
if (sym.kind == MDL) {
deprecationHandler.report(pos, LintWarnings.HasBeenDeprecatedModule(sym));
warningKey = LintWarnings.HasBeenDeprecatedModule(sym);
} else {
deprecationHandler.report(pos, LintWarnings.HasBeenDeprecated(sym, sym.location()));
warningKey = LintWarnings.HasBeenDeprecated(sym, sym.location());
}
}
if (warningKey != null)
log.mandatoryWarning(pos, warningKey);
}
/** Log a preview warning.
@ -276,7 +255,7 @@ public class Check {
*/
public void warnPreviewAPI(DiagnosticPosition pos, LintWarning warnKey) {
if (!importSuppression && !lint.isSuppressed(LintCategory.PREVIEW))
preview.reportPreviewWarning(pos, warnKey);
log.mandatoryWarning(pos, warnKey);
}
/** Log a preview warning.
@ -293,25 +272,15 @@ public class Check {
*/
public void warnUnchecked(DiagnosticPosition pos, LintWarning warnKey) {
if (!lint.isSuppressed(LintCategory.UNCHECKED))
uncheckedHandler.report(pos, warnKey);
log.mandatoryWarning(pos, warnKey);
}
/**
* Report any deferred diagnostics.
*/
public void reportDeferredDiagnostics() {
deprecationHandler.reportDeferredDiagnostic();
removalHandler.reportDeferredDiagnostic();
uncheckedHandler.reportDeferredDiagnostic();
}
/** Report a failure to complete a class.
* @param pos Position to be used for error reporting.
* @param ex The failure to report.
*/
public Type completionError(DiagnosticPosition pos, CompletionFailure ex) {
log.error(JCDiagnostic.DiagnosticFlag.NON_DEFERRABLE, pos, Errors.CantAccess(ex.sym, ex.getDetailValue()));
log.error(DiagnosticFlag.NON_DEFERRABLE, pos, Errors.CantAccess(ex.sym, ex.getDetailValue()));
return syms.errType;
}
@ -474,12 +443,6 @@ public class Check {
localClassNameIndexes.clear();
}
public void clear() {
deprecationHandler.clear();
removalHandler.clear();
uncheckedHandler.clear();
}
public void putCompiled(ClassSymbol csym) {
compiled.put(Pair.of(csym.packge().modle, csym.flatname), csym);
}

View File

@ -28,11 +28,12 @@ package com.sun.tools.javac.launcher;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import com.sun.tools.javac.api.JavacTool;
import com.sun.tools.javac.code.Preview;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.file.JavacFileManager;
import com.sun.tools.javac.resources.LauncherProperties.Errors;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Context.Factory;
import com.sun.tools.javac.util.Log;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
@ -120,8 +121,11 @@ final class MemoryContext {
}
var opts = options.forProgramCompilation();
var context = new Context();
MemoryPreview.registerInstance(context);
var task = compiler.getTask(out, memoryFileManager, null, opts, null, units, context);
// This suppresses diagnostics like "Note: Recompile with -Xlint:preview for details."
Log.instance(context).suppressAggregatedWarningNotes(LintCategory.PREVIEW);
var ok = task.call();
if (!ok) {
throw new Fault(Errors.CompilationFailed);
@ -269,19 +273,4 @@ final class MemoryContext {
controller.enableNativeAccess(module);
}
}
static class MemoryPreview extends Preview {
static void registerInstance(Context context) {
context.put(previewKey, (Factory<Preview>)MemoryPreview::new);
}
MemoryPreview(Context context) {
super(context);
}
@Override
public void reportDeferredDiagnostics() {
// suppress diagnostics like "Note: Recompile with -Xlint:preview for details."
}
}
}

View File

@ -55,10 +55,10 @@ import javax.tools.StandardLocation;
import com.sun.source.util.TaskEvent;
import com.sun.tools.javac.api.MultiTaskListener;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Source.Feature;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Symbol.CompletionFailure;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.code.Symbol.PackageSymbol;
import com.sun.tools.javac.comp.*;
import com.sun.tools.javac.comp.CompileStates.CompileState;
@ -85,10 +85,6 @@ import com.sun.tools.javac.util.Log.WriterKind;
import static com.sun.tools.javac.code.Kinds.Kind.*;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Symbol.ModuleSymbol;
import com.sun.tools.javac.resources.CompilerProperties.Errors;
import com.sun.tools.javac.resources.CompilerProperties.Fragments;
import com.sun.tools.javac.resources.CompilerProperties.Notes;
@ -274,10 +270,6 @@ public class JavaCompiler {
*/
protected Source source;
/** The preview language version.
*/
protected Preview preview;
/** The module for code generation.
*/
protected Gen gen;
@ -413,7 +405,6 @@ public class JavaCompiler {
log.error(Errors.CantAccess(ex.sym, ex.getDetailValue()));
}
source = Source.instance(context);
preview = Preview.instance(context);
attr = Attr.instance(context);
analyzer = Analyzer.instance(context);
chk = Check.instance(context);
@ -1852,8 +1843,7 @@ public class JavaCompiler {
else
log.warning(Warnings.ProcUseProcOrImplicit);
}
chk.reportDeferredDiagnostics();
preview.reportDeferredDiagnostics();
log.reportOutstandingNotes();
if (log.compressedOutput) {
log.mandatoryNote(null, Notes.CompressedDiags);
}

View File

@ -181,10 +181,10 @@ public class JavaTokenizer extends UnicodeReader {
protected void checkSourceLevel(int pos, Feature feature) {
if (preview.isPreview(feature) && !preview.isEnabled()) {
//preview feature without --preview flag, error
lexError(DiagnosticFlag.SOURCE_LEVEL, pos, preview.disabledError(feature));
lexError(pos, preview.disabledError(feature));
} else if (!feature.allowedInSource(source)) {
//incompatible source level, error
lexError(DiagnosticFlag.SOURCE_LEVEL, pos, feature.error(source.name));
lexError(pos, feature.error(source.name));
} else if (preview.isPreview(feature)) {
//use of preview feature, warn
preview.warnPreview(pos, feature);
@ -199,20 +199,7 @@ public class JavaTokenizer extends UnicodeReader {
*/
protected void lexError(int pos, JCDiagnostic.Error key) {
log.error(pos, key);
tk = TokenKind.ERROR;
errPos = pos;
}
/**
* Report an error at the given position using the provided arguments.
*
* @param flags diagnostic flags.
* @param pos position in input buffer.
* @param key error key to report.
*/
protected void lexError(DiagnosticFlag flags, int pos, JCDiagnostic.Error key) {
log.error(flags, pos, key);
if (flags != DiagnosticFlag.SOURCE_LEVEL) {
if (!key.hasFlag(DiagnosticFlag.SOURCE_LEVEL)) {
tk = TokenKind.ERROR;
}
errPos = pos;

View File

@ -5611,10 +5611,10 @@ public class JavacParser implements Parser {
protected void checkSourceLevel(int pos, Feature feature) {
if (preview.isPreview(feature) && !preview.isEnabled()) {
//preview feature without --preview flag, error
log.error(DiagnosticFlag.SOURCE_LEVEL, pos, preview.disabledError(feature));
log.error(pos, preview.disabledError(feature));
} else if (!feature.allowedInSource(source)) {
//incompatible source level, error
log.error(DiagnosticFlag.SOURCE_LEVEL, pos, feature.error(source.name));
log.error(pos, feature.error(source.name));
} else if (preview.isPreview(feature)) {
//use of preview feature, warn
preview.warnPreview(pos, feature);

View File

@ -1923,16 +1923,19 @@ compiler.warn.incubating.modules=\
# 0: symbol, 1: symbol
# lint: deprecation
# flags: aggregate
compiler.warn.has.been.deprecated=\
{0} in {1} has been deprecated
# 0: symbol, 1: symbol
# lint: removal
# flags: aggregate
compiler.warn.has.been.deprecated.for.removal=\
{0} in {1} has been deprecated and marked for removal
# 0: symbol
# lint: preview
# flags: aggregate
compiler.warn.is.preview=\
{0} is a preview API and may be removed in a future release.
@ -1943,6 +1946,7 @@ compiler.err.is.preview=\
# 0: symbol
# lint: preview
# flags: aggregate
compiler.warn.is.preview.reflective=\
{0} is a reflective preview API and may be removed in a future release.
@ -1954,11 +1958,13 @@ compiler.warn.restricted.method=\
# 0: symbol
# lint: deprecation
# flags: aggregate
compiler.warn.has.been.deprecated.module=\
module {0} has been deprecated
# 0: symbol
# lint: removal
# flags: aggregate
compiler.warn.has.been.deprecated.for.removal.module=\
module {0} has been deprecated and marked for removal
@ -2357,11 +2363,13 @@ compiler.warn.unchecked.assign=\
# 0: symbol, 1: type
# lint: unchecked
# flags: aggregate
compiler.warn.unchecked.assign.to.var=\
unchecked assignment to variable {0} as member of raw type {1}
# 0: symbol, 1: type
# lint: unchecked
# flags: aggregate
compiler.warn.unchecked.call.mbr.of.raw.type=\
unchecked call to {0} as a member of the raw type {1}
@ -2371,6 +2379,7 @@ compiler.warn.unchecked.cast.to.type=\
# 0: kind name, 1: name, 2: object, 3: object, 4: kind name, 5: symbol
# lint: unchecked
# flags: aggregate
compiler.warn.unchecked.meth.invocation.applied=\
unchecked method invocation: {0} {1} in {4} {5} is applied to given types\n\
required: {2}\n\
@ -2378,11 +2387,13 @@ compiler.warn.unchecked.meth.invocation.applied=\
# 0: type
# lint: unchecked
# flags: aggregate
compiler.warn.unchecked.generic.array.creation=\
unchecked generic array creation for varargs parameter of type {0}
# 0: type
# lint: unchecked
# flags: aggregate
compiler.warn.unchecked.varargs.non.reifiable.type=\
Possible heap pollution from parameterized vararg type {0}
@ -2781,6 +2792,7 @@ compiler.misc.prob.found.req=\
# 0: message segment, 1: type, 2: type
# lint: unchecked
# flags: aggregate
compiler.warn.prob.found.req=\
{0}\n\
required: {2}\n\
@ -3177,12 +3189,14 @@ compiler.err.override.incompatible.ret=\
# 0: message segment, 1: type, 2: type
# lint: unchecked
# flags: aggregate
compiler.warn.override.unchecked.ret=\
{0}\n\
return type requires unchecked conversion from {1} to {2}
# 0: message segment, 1: type
# lint: unchecked
# flags: aggregate
compiler.warn.override.unchecked.thrown=\
{0}\n\
overridden method does not throw {1}
@ -3246,11 +3260,13 @@ compiler.misc.inapplicable.method=\
########################################
# 0: message segment (feature), 1: string (found version), 2: string (expected version)
# flags: source-level
compiler.err.feature.not.supported.in.source=\
{0} is not supported in -source {1}\n\
(use -source {2} or higher to enable {0})
# 0: message segment (feature), 1: string (found version), 2: string (expected version)
# flags: source-level
compiler.err.feature.not.supported.in.source.plural=\
{0} are not supported in -source {1}\n\
(use -source {2} or higher to enable {0})
@ -3266,11 +3282,13 @@ compiler.misc.feature.not.supported.in.source.plural=\
(use -source {2} or higher to enable {0})
# 0: message segment (feature)
# flags: source-level
compiler.err.preview.feature.disabled=\
{0} is a preview feature and is disabled by default.\n\
(use --enable-preview to enable {0})
# 0: message segment (feature)
# flags: source-level
compiler.err.preview.feature.disabled.plural=\
{0} are a preview feature and are disabled by default.\n\
(use --enable-preview to enable {0})
@ -3282,11 +3300,13 @@ compiler.err.preview.feature.disabled.classfile=\
# 0: message segment (feature)
# lint: preview
# flags: aggregate
compiler.warn.preview.feature.use=\
{0} is a preview feature and may be removed in a future release.
# 0: message segment (feature)
# lint: preview
# flags: aggregate
compiler.warn.preview.feature.use.plural=\
{0} are a preview feature and may be removed in a future release.
@ -4249,6 +4269,7 @@ compiler.err.incorrect.number.of.nested.patterns=\
# 0: kind name, 1: symbol
# lint: preview
# flags: aggregate
compiler.warn.declared.using.preview=\
{0} {1} is declared using a preview feature, which may be removed in a future release.

View File

@ -25,6 +25,7 @@
package com.sun.tools.javac.util;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.function.UnaryOperator;
import java.util.Locale;
@ -237,7 +238,7 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
*/
public JCDiagnostic create(
DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(EnumSet.noneOf(DiagnosticFlag.class), source, pos, DiagnosticInfo.of(kind, prefix, key, args));
return create(EnumSet.noneOf(DiagnosticFlag.class), source, pos, DiagnosticInfo.of(kind, null, prefix, key, args));
}
/**
@ -252,7 +253,7 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
*/
public JCDiagnostic create(
DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, UnaryOperator<JCDiagnostic> rewriter, Object... args) {
return create(EnumSet.noneOf(DiagnosticFlag.class), source, pos, DiagnosticInfo.of(kind, prefix, key, args), rewriter);
return create(EnumSet.noneOf(DiagnosticFlag.class), source, pos, DiagnosticInfo.of(kind, null, prefix, key, args), rewriter);
}
/**
@ -279,7 +280,7 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
*/
public JCDiagnostic create(DiagnosticType kind,
LintCategory lc, Set<DiagnosticFlag> flags, DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) {
return create(flags, source, pos, DiagnosticInfo.of(kind, lc, prefix, key, args));
return create(flags, source, pos, DiagnosticInfo.of(kind, null, lc, prefix, key, args));
}
/**
@ -303,7 +304,8 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
//replace all nested FragmentKey with full-blown JCDiagnostic objects
LintCategory category = diagnosticInfo instanceof LintWarning lintWarning ?
lintWarning.category : null;
return DiagnosticInfo.of(diagnosticInfo.type, category, diagnosticInfo.prefix, diagnosticInfo.code,
return DiagnosticInfo.of(diagnosticInfo.type, diagnosticInfo.flags,
category, diagnosticInfo.prefix, diagnosticInfo.code,
Stream.of(diagnosticInfo.args).map(o -> {
return (o instanceof Fragment frag) ?
fragment(frag) : o;
@ -314,28 +316,28 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
* Create a new error key.
*/
public Error errorKey(String code, Object... args) {
return (Error)DiagnosticInfo.of(ERROR, prefix, code, args);
return (Error)DiagnosticInfo.of(ERROR, null, prefix, code, args);
}
/**
* Create a new warning key.
*/
Warning warningKey(LintCategory lintCategory, String code, Object... args) {
return (Warning)DiagnosticInfo.of(WARNING, lintCategory, prefix, code, args);
return (Warning)DiagnosticInfo.of(WARNING, null, lintCategory, prefix, code, args);
}
/**
* Create a new note key.
*/
public Note noteKey(String code, Object... args) {
return (Note)DiagnosticInfo.of(NOTE, prefix, code, args);
return (Note)DiagnosticInfo.of(NOTE, null, prefix, code, args);
}
/**
* Create a new fragment key.
*/
Fragment fragmentKey(String code, Object... args) {
return (Fragment)DiagnosticInfo.of(FRAGMENT, prefix, code, args);
return (Fragment)DiagnosticInfo.of(FRAGMENT, null, prefix, code, args);
}
}
@ -351,6 +353,7 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
public static JCDiagnostic fragment(String key, Object... args) {
return new JCDiagnostic(getFragmentFormatter(),
DiagnosticInfo.of(FRAGMENT,
null,
null,
"compiler",
key,
@ -447,6 +450,9 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
RECOVERABLE,
NON_DEFERRABLE,
COMPRESSED,
/** Flags mandatory warnings that should pass through a mandatory warning aggregator.
*/
AGGREGATE,
/** Flag for diagnostics that were reported through API methods.
*/
API,
@ -503,6 +509,9 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
/** The diagnostic kind (i.e. error). */
DiagnosticType type;
/** A set of diagnostic flags to be automatically added to newly created JCDiagnostics. */
Set<DiagnosticFlag> flags;
/** The diagnostic prefix (i.e. 'javac'); used to compute full resource key. */
String prefix;
@ -513,8 +522,9 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
/** The diagnostic arguments. */
Object[] args;
private DiagnosticInfo(DiagnosticType type, String prefix, String code, Object... args) {
private DiagnosticInfo(DiagnosticType type, Set<DiagnosticFlag> flags, String prefix, String code, Object... args) {
this.type = type;
this.flags = flags != null ? flags : EnumSet.noneOf(DiagnosticFlag.class);
this.prefix = prefix;
this.code = code;
this.args = args;
@ -530,22 +540,24 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
/**
* Static factory method; build a custom diagnostic key using given kind, prefix, code and args.
*/
public static DiagnosticInfo of(DiagnosticType type, String prefix, String code, Object... args) {
return of(type, null, prefix, code, args);
public static DiagnosticInfo of(DiagnosticType type, Set<DiagnosticFlag> flags,
String prefix, String code, Object... args) {
return of(type, flags, null, prefix, code, args);
}
public static DiagnosticInfo of(DiagnosticType type, LintCategory lc, String prefix, String code, Object... args) {
public static DiagnosticInfo of(DiagnosticType type, Set<DiagnosticFlag> flags,
LintCategory lc, String prefix, String code, Object... args) {
switch (type) {
case ERROR:
return new Error(prefix, code, args);
return new Error(flags, prefix, code, args);
case WARNING:
return lc == null ?
new Warning(prefix, code, args) :
new LintWarning(lc, prefix, code, args);
new Warning(flags, prefix, code, args) :
new LintWarning(flags, lc, prefix, code, args);
case NOTE:
return new Note(prefix, code, args);
return new Note(flags, prefix, code, args);
case FRAGMENT:
return new Fragment(prefix, code, args);
return new Fragment(flags, prefix, code, args);
default:
Assert.error("Wrong diagnostic type: " + type);
return null;
@ -569,14 +581,18 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
public void setArgs(Object[] args) {
this.args = args;
}
public boolean hasFlag(DiagnosticFlag flag) {
return flags.contains(flag);
}
}
/**
* Class representing error diagnostic keys.
*/
public static final class Error extends DiagnosticInfo {
public Error(String prefix, String key, Object... args) {
super(DiagnosticType.ERROR, prefix, key, args);
public Error(Set<DiagnosticFlag> flags, String prefix, String key, Object... args) {
super(DiagnosticType.ERROR, flags, prefix, key, args);
}
}
@ -584,8 +600,8 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
* Class representing warning diagnostic keys.
*/
public static sealed class Warning extends DiagnosticInfo {
public Warning(String prefix, String key, Object... args) {
super(DiagnosticType.WARNING, prefix, key, args);
public Warning(Set<DiagnosticFlag> flags, String prefix, String key, Object... args) {
super(DiagnosticType.WARNING, flags, prefix, key, args);
}
}
@ -595,8 +611,8 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
public static final class LintWarning extends Warning {
final LintCategory category;
public LintWarning(LintCategory category, String prefix, String key, Object... args) {
super(prefix, key, args);
public LintWarning(Set<DiagnosticFlag> flags, LintCategory category, String prefix, String key, Object... args) {
super(flags, prefix, key, args);
this.category = category;
}
@ -609,8 +625,8 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
* Class representing note diagnostic keys.
*/
public static final class Note extends DiagnosticInfo {
public Note(String prefix, String key, Object... args) {
super(DiagnosticType.NOTE, prefix, key, args);
public Note(Set<DiagnosticFlag> flags, String prefix, String key, Object... args) {
super(DiagnosticType.NOTE, flags, prefix, key, args);
}
}
@ -618,8 +634,8 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
* Class representing fragment diagnostic keys.
*/
public static final class Fragment extends DiagnosticInfo {
public Fragment(String prefix, String key, Object... args) {
super(DiagnosticType.FRAGMENT, prefix, key, args);
public Fragment(Set<DiagnosticFlag> flags, String prefix, String key, Object... args) {
super(DiagnosticType.FRAGMENT, flags, prefix, key, args);
}
}
@ -664,6 +680,8 @@ public class JCDiagnostic implements Diagnostic<JavaFileObject> {
this.source = source;
this.position = pos;
this.rewriter = rewriter;
this.flags.addAll(diagnosticInfo.flags);
}
/**

View File

@ -30,6 +30,7 @@ import java.util.ArrayList;
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;
@ -41,15 +42,18 @@ import javax.tools.DiagnosticListener;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.api.DiagnosticFormatter;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.main.Main;
import com.sun.tools.javac.main.Option;
import com.sun.tools.javac.tree.EndPosTable;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticInfo;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
import static com.sun.tools.javac.main.Option.*;
import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;
/** A class for error logs. Reports errors and warnings, and
* keeps track of error numbers and positions.
@ -148,7 +152,7 @@ public class Log extends AbstractLog {
}
private boolean deferrable(JCDiagnostic diag) {
return !(diag.isFlagSet(DiagnosticFlag.NON_DEFERRABLE) && passOnNonDeferrable) && filter.test(diag);
return !(diag.isFlagSet(NON_DEFERRABLE) && passOnNonDeferrable) && filter.test(diag);
}
@Override
@ -237,6 +241,16 @@ public class Log extends AbstractLog {
*/
private JavacMessages messages;
/**
* The compilation context.
*/
private final Context context;
/**
* The root {@link Lint} singleton.
*/
private Lint rootLint;
/**
* Handler for initial dispatch of diagnostics.
*/
@ -334,6 +348,7 @@ public class Log extends AbstractLog {
private Log(Context context, Map<WriterKind, PrintWriter> writers) {
super(JCDiagnostic.Factory.instance(context));
context.put(logKey, this);
this.context = context;
this.writers = writers;
@SuppressWarnings("unchecked") // FIXME
@ -517,7 +532,7 @@ public class Log extends AbstractLog {
if (!shouldReport(file, d.getIntPosition()))
return false;
if (!d.isFlagSet(DiagnosticFlag.SOURCE_LEVEL))
if (!d.isFlagSet(SOURCE_LEVEL))
return true;
Pair<JavaFileObject, List<String>> coords = new Pair<>(file, getCode(d));
@ -681,7 +696,48 @@ public class Log extends AbstractLog {
@Override
public void report(JCDiagnostic diagnostic) {
diagnosticHandler.report(diagnostic);
}
}
// Obtain root Lint singleton lazily to avoid init loops
private Lint rootLint() {
if (rootLint == null)
rootLint = Lint.instance(context);
return rootLint;
}
// Mandatory Warnings
private final EnumMap<LintCategory, WarningAggregator> aggregators = new EnumMap<>(LintCategory.class);
private final EnumSet<LintCategory> suppressedDeferredMandatory = EnumSet.noneOf(LintCategory.class);
/**
* Suppress aggregated mandatory warning notes for the specified category.
*/
public void suppressAggregatedWarningNotes(LintCategory category) {
suppressedDeferredMandatory.add(category);
}
/**
* Report any remaining unreported aggregated mandatory warning notes.
*/
public void reportOutstandingNotes() {
aggregators.entrySet().stream()
.filter(entry -> !suppressedDeferredMandatory.contains(entry.getKey()))
.map(Map.Entry::getValue)
.map(WarningAggregator::aggregationNotes)
.flatMap(List::stream)
.forEach(this::report);
aggregators.clear();
}
private WarningAggregator aggregatorFor(LintCategory lc) {
return switch (lc) {
case PREVIEW -> aggregators.computeIfAbsent(lc, c -> new WarningAggregator(this, Source.instance(context), c));
case DEPRECATION -> aggregators.computeIfAbsent(lc, c -> new WarningAggregator(this, null, c, "deprecated"));
default -> aggregators.computeIfAbsent(lc, c -> new WarningAggregator(this, null, c));
};
}
/**
* Reset the state of this instance.
@ -695,14 +751,19 @@ public class Log extends AbstractLog {
nsuppressedwarns = 0;
while (diagnosticHandler.prev != null)
popDiagnosticHandler(diagnosticHandler);
aggregators.clear();
suppressedDeferredMandatory.clear();
}
// DefaultDiagnosticHandler
/**
* Common diagnostic handling.
* The diagnostic is counted, and depending on the options and how many diagnostics have been
* reported so far, the diagnostic may be handed off to writeDiagnostic.
*/
private class DefaultDiagnosticHandler extends DiagnosticHandler {
@Override
public void report(JCDiagnostic diagnostic) {
if (expectDiagKeys != null)
@ -727,6 +788,16 @@ public class Log extends AbstractLog {
break;
case WARNING:
// Apply the appropriate mandatory warning aggregator, if needed
if (diagnostic.isFlagSet(AGGREGATE)) {
LintCategory category = diagnostic.getLintCategory();
boolean verbose = rootLint().isEnabled(category);
if (!aggregatorFor(category).aggregate(diagnostic, verbose))
return;
}
// Emit warning unless not mandatory and warnings are disabled
if (emitWarnings || diagnostic.isMandatory()) {
if (nwarnings < MaxWarnings) {
writeDiagnostic(diagnostic);
@ -738,8 +809,7 @@ public class Log extends AbstractLog {
break;
case ERROR:
if (diagnostic.isFlagSet(DiagnosticFlag.API) ||
shouldReport(diagnostic)) {
if (diagnostic.isFlagSet(API) || shouldReport(diagnostic)) {
if (nerrors < MaxErrors) {
writeDiagnostic(diagnostic);
nerrors++;
@ -749,7 +819,7 @@ public class Log extends AbstractLog {
}
break;
}
if (diagnostic.isFlagSet(JCDiagnostic.DiagnosticFlag.COMPRESSED)) {
if (diagnostic.isFlagSet(COMPRESSED)) {
compressedOutput = true;
}
}

View File

@ -25,11 +25,14 @@
package com.sun.tools.javac.util;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Lint;
import com.sun.tools.javac.code.Lint.LintCategory;
import com.sun.tools.javac.code.Source;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
@ -39,16 +42,10 @@ import com.sun.tools.javac.util.JCDiagnostic.Warning;
/**
* A handler to process mandatory warnings, setting up a deferred diagnostic
* An aggregator for warnings, setting up a deferred diagnostic
* to be printed at the end of the compilation if some warnings get suppressed
* because too many warnings have already been generated.
*
* <p>
* Note that the SuppressWarnings annotation can be used to suppress warnings
* about conditions that would otherwise merit a warning. Such processing
* is done when the condition is detected, and in those cases, no call is
* made on any API to generate a warning at all. In consequence, this handler only
* Returns to handle those warnings that JLS says must be generated.
* because the lint category is not enabled or too many warnings have already
* been generated.
*
* <p>
* All warnings must be in the same {@link LintCategory} provided to the constructor.
@ -58,12 +55,11 @@ import com.sun.tools.javac.util.JCDiagnostic.Warning;
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class MandatoryWarningHandler {
class WarningAggregator {
/**
* The kinds of different deferred diagnostics that might be generated
* if a mandatory warning is suppressed because too many warnings have
* already been output.
* if a warning is suppressed because too many warnings have already been output.
*
* The parameter is a fragment used to build an I18N message key for Log.
*/
@ -105,64 +101,50 @@ public class MandatoryWarningHandler {
/**
* Create a handler for mandatory warnings.
* Create an aggregator for 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 lc The lint category for all warnings
*/
public MandatoryWarningHandler(Log log, Source source, boolean verbose, boolean enforceMandatory, LintCategory lc) {
this(log, source, verbose, enforceMandatory, lc, null);
public WarningAggregator(Log log, Source source, LintCategory lc) {
this(log, source, lc, null);
}
/**
* Create a handler for mandatory warnings.
* Create an aggregator for 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 lc The lint category for all warnings
* @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, LintCategory lc, String prefix) {
public WarningAggregator(Log log, Source source, LintCategory lc, String prefix) {
this.log = log;
this.source = source;
this.verbose = verbose;
this.prefix = prefix != null ? prefix : lc.option;
this.enforceMandatory = enforceMandatory;
this.lintCategory = lc;
}
/**
* Report a mandatory warning.
* Aggregate a warning and determine whether to emit it.
*
* @param pos source code position
* @param warnKey lint warning
* @param diagnostic the warning
* @param verbose whether the warning's lint category is enabled
* @return true if diagnostic should be emitted, otherwise false
*/
public void report(DiagnosticPosition pos, LintWarning warnKey) {
public boolean aggregate(JCDiagnostic diagnostic, boolean verbose) {
Assert.check(diagnostic.getLintCategory() == lintCategory);
JavaFileObject currentSource = log.currentSourceFile();
Assert.check(warnKey.getLintCategory() == lintCategory);
if (verbose) {
if (sourcesWithReportedWarnings == null)
sourcesWithReportedWarnings = new HashSet<>();
if (log.nwarnings < log.MaxWarnings) {
// generate message and remember the source file
logMandatoryWarning(pos, warnKey);
sourcesWithReportedWarnings.add(currentSource);
anyWarningEmitted = true;
return true;
} else if (deferredDiagnosticKind == null) {
// set up deferred message
if (sourcesWithReportedWarnings.contains(currentSource)) {
@ -194,30 +176,36 @@ public class MandatoryWarningHandler {
deferredDiagnosticArg = null;
}
}
return false;
}
/**
* Report any diagnostic that might have been deferred by previous calls of report().
* Build and return any accumulated aggregation notes.
*/
public void reportDeferredDiagnostic() {
public List<JCDiagnostic> aggregationNotes() {
List<JCDiagnostic> list = new ArrayList<>(2);
if (deferredDiagnosticKind != null) {
if (deferredDiagnosticArg == null) {
if (source != null) {
logMandatoryNote(deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix), source);
addNote(list, deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix), source);
} else {
logMandatoryNote(deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix));
addNote(list, deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix));
}
} else {
if (source != null) {
logMandatoryNote(deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix), deferredDiagnosticArg, source);
addNote(list, deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix), deferredDiagnosticArg, source);
} else {
logMandatoryNote(deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix), deferredDiagnosticArg);
addNote(list, deferredDiagnosticSource, deferredDiagnosticKind.getKey(prefix), deferredDiagnosticArg);
}
}
if (!verbose)
logMandatoryNote(deferredDiagnosticSource, prefix + ".recompile");
if (!anyWarningEmitted)
addNote(list, deferredDiagnosticSource, prefix + ".recompile");
}
return list;
}
private void addNote(List<JCDiagnostic> list, JavaFileObject file, String msg, Object... args) {
list.add(log.diags.mandatoryNote(log.getSource(file), new Note(null, "compiler", msg, args)));
}
/**
@ -226,12 +214,6 @@ public class MandatoryWarningHandler {
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.
*/
@ -268,9 +250,10 @@ public class MandatoryWarningHandler {
private Object deferredDiagnosticArg;
/**
* True if mandatory warnings and notes are being enforced.
* Whether we have actually emitted a warning or just deferred everything.
* In the latter case, the "recompile" notice is included in the summary.
*/
private final boolean enforceMandatory;
private boolean anyWarningEmitted;
/**
* A LintCategory to be included in point-of-use diagnostics to indicate
@ -278,28 +261,6 @@ public class MandatoryWarningHandler {
*/
private final LintCategory lintCategory;
/**
* Reports a mandatory warning to the log. If mandatory warnings
* are not being enforced, treat this as an ordinary warning.
*/
private void logMandatoryWarning(DiagnosticPosition pos, LintWarning warnKey) {
if (enforceMandatory)
log.mandatoryWarning(pos, warnKey);
else
log.warning(pos, warnKey);
}
/**
* Reports a mandatory note to the log. If mandatory notes are
* not being enforced, treat this as an ordinary note.
*/
private void logMandatoryNote(JavaFileObject file, String msg, Object... args) {
if (enforceMandatory)
log.mandatoryNote(file, new Note("compiler", msg, args));
else
log.note(file, new Note("compiler", msg, args));
}
public void clear() {
sourcesWithReportedWarnings = null;
deferredDiagnosticKind = null;