diff --git a/make/langtools/tools/propertiesparser/gen/ClassGenerator.java b/make/langtools/tools/propertiesparser/gen/ClassGenerator.java index e869d60bbc569..247537b467699 100644 --- a/make/langtools/tools/propertiesparser/gen/ClassGenerator.java +++ b/make/langtools/tools/propertiesparser/gen/ClassGenerator.java @@ -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.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 @@ enum StubKind { 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 @@ List generateFactoryMethodsAndFields(FactoryKind k, String key, Message .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 @@ List generateFactoryMethodsAndFields(FactoryKind k, String key, Message 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(".")) + "\"", diff --git a/make/langtools/tools/propertiesparser/parser/Message.java b/make/langtools/tools/propertiesparser/parser/Message.java index 3c1191084ec1c..fb0809fb1bdc0 100644 --- a/make/langtools/tools/propertiesparser/parser/Message.java +++ b/make/langtools/tools/propertiesparser/parser/Message.java @@ -32,7 +32,8 @@ * 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 List getLines(boolean includeAllPrecedingComments) { 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; } diff --git a/make/langtools/tools/propertiesparser/parser/MessageLine.java b/make/langtools/tools/propertiesparser/parser/MessageLine.java index c73021e08274e..f1a29c2025569 100644 --- a/make/langtools/tools/propertiesparser/parser/MessageLine.java +++ b/make/langtools/tools/propertiesparser/parser/MessageLine.java @@ -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 String lintCategory() { } } + 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("\\"); } diff --git a/make/langtools/tools/propertiesparser/resources/templates.properties b/make/langtools/tools/propertiesparser/resources/templates.properties index 991739aa40326..81a9be2552c26 100644 --- a/make/langtools/tools/propertiesparser/resources/templates.properties +++ b/make/langtools/tools/propertiesparser/resources/templates.properties @@ -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} @@ -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}) + diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java index 87bc64c4e1976..6214c3775d382 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/api/JavacTaskPool.java @@ -272,8 +272,6 @@ void clear() { ((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(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index d1e64e90a07cc..c70202fd942e7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -40,7 +40,6 @@ 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 @@ protected Preview(Context context) { 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 void warnPreview(DiagnosticPosition pos, Feature feature) { 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 void markUsesPreview(DiagnosticPosition pos) { 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 boolean declaredUsingPreviewFeature(Symbol sym) { 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); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 9c9672151c7da..8819acbe67ee3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -79,7 +79,6 @@ 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 void visitTypeTest(JCInstanceOf tree) { !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 void visitTypeTest(JCInstanceOf tree) { 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) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index 89ab5b13dd145..ddfeea2351531 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -164,18 +164,6 @@ 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, 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 @@ protected Check(Context context) { */ private Map,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 @@ MethodSymbol setMethod(MethodSymbol newMethod) { * @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 @@ void warnDeprecated(DiagnosticPosition pos, Symbol sym) { */ 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 void warnRestrictedAPI(DiagnosticPosition pos, Symbol sym) { */ 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 void newRound() { 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); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/MemoryContext.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/MemoryContext.java index 5fa76c14d3f8f..3f3f5e2f27b67 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/MemoryContext.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/MemoryContext.java @@ -28,11 +28,12 @@ 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 @@ void compileProgram() throws Fault { } 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 @@ private void enableNativeAccess(ModuleLayer.Controller controller, boolean shoul controller.enableNativeAccess(module); } } - - static class MemoryPreview extends Preview { - static void registerInstance(Context context) { - context.put(previewKey, (Factory)MemoryPreview::new); - } - - MemoryPreview(Context context) { - super(context); - } - - @Override - public void reportDeferredDiagnostics() { - // suppress diagnostics like "Note: Recompile with -Xlint:preview for details." - } - } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 52979ab16b412..214f72984e508 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -55,10 +55,10 @@ 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 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 @@ else if (option.equals("class")) */ protected Source source; - /** The preview language version. - */ - protected Preview preview; - /** The module for code generation. */ protected Gen gen; @@ -413,7 +405,6 @@ public JavaCompiler(Context context) { 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 void reportDeferredDiagnostics() { else log.warning(Warnings.ProcUseProcOrImplicit); } - chk.reportDeferredDiagnostics(); - preview.reportDeferredDiagnostics(); + log.reportOutstandingNotes(); if (log.compressedOutput) { log.mandatoryNote(null, Notes.CompressedDiags); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index d799975a76aef..f3d0837398c2f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -181,10 +181,10 @@ protected JavaTokenizer(ScannerFactory fac, char[] array, int length) { 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 @@ protected void checkSourceLevel(int pos, Feature feature) { */ 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; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 7ebcd0c844b2a..b63374d9c6dc3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -5611,10 +5611,10 @@ void checkSourceLevel(Feature feature) { 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); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index ead48ee62bf73..6c6f80ef58c66 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -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. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java index 220ec856d62fd..5d10626f944a0 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java @@ -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 JCDiagnostic fragment(Fragment fragmentKey) { */ 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 JCDiagnostic create( */ public JCDiagnostic create( DiagnosticType kind, DiagnosticSource source, DiagnosticPosition pos, String key, UnaryOperator 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 JCDiagnostic create( */ public JCDiagnostic create(DiagnosticType kind, LintCategory lc, Set 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 @@ DiagnosticInfo normalize(DiagnosticInfo diagnosticInfo) { //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 @@ DiagnosticInfo normalize(DiagnosticInfo diagnosticInfo) { * 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 @@ Fragment fragmentKey(String code, Object... args) { public static JCDiagnostic fragment(String key, Object... args) { return new JCDiagnostic(getFragmentFormatter(), DiagnosticInfo.of(FRAGMENT, + null, null, "compiler", key, @@ -447,6 +450,9 @@ public enum DiagnosticFlag { 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 abstract static class DiagnosticInfo { /** The diagnostic kind (i.e. error). */ DiagnosticType type; + /** A set of diagnostic flags to be automatically added to newly created JCDiagnostics. */ + Set flags; + /** The diagnostic prefix (i.e. 'javac'); used to compute full resource key. */ String prefix; @@ -513,8 +522,9 @@ public abstract static class DiagnosticInfo { /** The diagnostic arguments. */ Object[] args; - private DiagnosticInfo(DiagnosticType type, String prefix, String code, Object... args) { + private DiagnosticInfo(DiagnosticType type, Set 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 String key() { /** * 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 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 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 Object[] getArgs() { 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 flags, String prefix, String key, Object... args) { + super(DiagnosticType.ERROR, flags, prefix, key, args); } } @@ -584,8 +600,8 @@ public Error(String prefix, String key, Object... args) { * 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 flags, String prefix, String key, Object... args) { + super(DiagnosticType.WARNING, flags, prefix, key, args); } } @@ -595,8 +611,8 @@ public Warning(String prefix, String key, Object... args) { 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 flags, LintCategory category, String prefix, String key, Object... args) { + super(flags, prefix, key, args); this.category = category; } @@ -609,8 +625,8 @@ public LintCategory getLintCategory() { * 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 flags, String prefix, String key, Object... args) { + super(DiagnosticType.NOTE, flags, prefix, key, args); } } @@ -618,8 +634,8 @@ public Note(String prefix, String key, Object... args) { * 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 flags, String prefix, String key, Object... args) { + super(DiagnosticType.FRAGMENT, flags, prefix, key, args); } } @@ -664,6 +680,8 @@ protected JCDiagnostic(DiagnosticFormatter formatter, this.source = source; this.position = pos; this.rewriter = rewriter; + + this.flags.addAll(diagnosticInfo.flags); } /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index fd51729bf2139..8c60de58bb82d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -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; @@ -41,15 +42,18 @@ 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 DeferredDiagnosticHandler(Predicate filter, boolean passOnN } 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 enum WriterKind { NOTICE, WARNING, ERROR, STDOUT, STDERR } */ 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 @@ private static Map initWriters(PrintWriter out, PrintWr private Log(Context context, Map writers) { super(JCDiagnostic.Factory.instance(context)); context.put(logKey, this); + this.context = context; this.writers = writers; @SuppressWarnings("unchecked") // FIXME @@ -517,7 +532,7 @@ private boolean shouldReport(JCDiagnostic d) { if (!shouldReport(file, d.getIntPosition())) return false; - if (!d.isFlagSet(DiagnosticFlag.SOURCE_LEVEL)) + if (!d.isFlagSet(SOURCE_LEVEL)) return true; Pair> coords = new Pair<>(file, getCode(d)); @@ -681,7 +696,48 @@ public void strictWarning(DiagnosticPosition pos, String key, Object ... args) { @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 aggregators = new EnumMap<>(LintCategory.class); + + private final EnumSet 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 void clear() { 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 void report(JCDiagnostic diagnostic) { 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 void report(JCDiagnostic diagnostic) { 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 void report(JCDiagnostic diagnostic) { } break; } - if (diagnostic.isFlagSet(JCDiagnostic.DiagnosticFlag.COMPRESSED)) { + if (diagnostic.isFlagSet(COMPRESSED)) { compressedOutput = true; } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningHandler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/WarningAggregator.java similarity index 68% rename from src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningHandler.java rename to src/jdk.compiler/share/classes/com/sun/tools/javac/util/WarningAggregator.java index 046740ddc3028..2bb8d2e2754f7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningHandler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/WarningAggregator.java @@ -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 @@ /** - * 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. - * - *

- * 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. * *

* All warnings must be in the same {@link LintCategory} provided to the constructor. @@ -58,12 +55,11 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -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 @@ private enum DeferredDiagnosticKind { /** - * 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 void report(DiagnosticPosition pos, LintWarning warnKey) { 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 aggregationNotes() { + List 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 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 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. */ @@ -268,9 +250,10 @@ public void reportDeferredDiagnostic() { 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 void reportDeferredDiagnostic() { */ 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;