From 75d9edf5160486744d39fe85226bf571987fea13 Mon Sep 17 00:00:00 2001 From: "Archie L. Cobbs" Date: Fri, 13 Jun 2025 14:25:48 -0500 Subject: [PATCH 1/6] Refactor MandatoryWarningHandler to just be an aggregator. --- .../sun/tools/javac/api/JavacTaskPool.java | 2 - .../com/sun/tools/javac/code/Preview.java | 32 ++---- .../com/sun/tools/javac/comp/Check.java | 57 ++------- .../tools/javac/launcher/MemoryContext.java | 23 +--- .../sun/tools/javac/main/JavaCompiler.java | 14 +-- .../com/sun/tools/javac/util/AbstractLog.java | 31 +++-- .../sun/tools/javac/util/JCDiagnostic.java | 30 +---- .../classes/com/sun/tools/javac/util/Log.java | 85 ++++++++++++-- ...r.java => MandatoryWarningAggregator.java} | 108 +++++++----------- 9 files changed, 166 insertions(+), 216 deletions(-) rename src/jdk.compiler/share/classes/com/sun/tools/javac/util/{MandatoryWarningHandler.java => MandatoryWarningAggregator.java} (72%) 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..0b06863cd962f 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 @@ -34,13 +34,13 @@ import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.Error; 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 +71,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 +102,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,9 +172,11 @@ 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())); + LintWarnings.PreviewFeatureUse(feature.nameFragment()), + DiagnosticFlag.AGGREGATE); } /** @@ -203,10 +201,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 +263,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(DiagnosticFlag.SOURCE_LEVEL, pos, disabledError(feature)); } else { if (!feature.allowedInSource(source)) { - log.error(JCDiagnostic.DiagnosticFlag.SOURCE_LEVEL, pos, - feature.error(source.name)); + log.error(DiagnosticFlag.SOURCE_LEVEL, 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/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index 89ab5b13dd145..68d1a1125ded0 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()); } } + Optional.ofNullable(warningKey) + .ifPresent(key -> log.mandatoryWarning(pos, key, DiagnosticFlag.AGGREGATE)); } /** 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, DiagnosticFlag.AGGREGATE); } /** 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, DiagnosticFlag.AGGREGATE); } - /** - * 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/util/AbstractLog.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java index 59730448bf53a..d7d328ddae4a3 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 com.sun.tools.javac.util; +import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import javax.tools.JavaFileObject; @@ -159,35 +160,45 @@ public void error(DiagnosticFlag flag, int pos, Error errorKey) { * maximum number of warnings has been reached. * * @param warningKey The key for the localized warning message. + * @param flags Any additional flags required */ - public void warning(Warning warningKey) { - report(diags.warning(source, null, warningKey)); + public void warning(Warning warningKey, DiagnosticFlag... flags) { + warning(null, warningKey, flags); } /** Report a warning, unless suppressed by the -nowarn option or the * maximum number of warnings has been reached. * @param pos The source position at which to report the warning. * @param warningKey The key for the localized warning message. + * @param flags Any additional flags required */ - public void warning(DiagnosticPosition pos, Warning warningKey) { - report(diags.warning(source, pos, warningKey)); + public void warning(int pos, Warning warningKey, DiagnosticFlag... flags) { + warning(wrap(pos), warningKey, flags); } /** Report a warning, unless suppressed by the -nowarn option or the * maximum number of warnings has been reached. * @param pos The source position at which to report the warning. * @param warningKey The key for the localized warning message. + * @param flags Any additional flags required */ - public void warning(int pos, Warning warningKey) { - report(diags.warning(source, wrap(pos), warningKey)); + public void warning(DiagnosticPosition pos, Warning warningKey, DiagnosticFlag... flags) { + EnumSet flagSet = EnumSet.noneOf(DiagnosticFlag.class); + for (DiagnosticFlag flag : flags) + flagSet.add(flag); + report(diags.create(flagSet, source, pos, warningKey)); } - /** Report a warning. + /** Report a mandatory warning. * @param pos The source position at which to report the warning. * @param warningKey The key for the localized warning message. + * @param flags Any additional flags required */ - public void mandatoryWarning(DiagnosticPosition pos, Warning warningKey) { - report(diags.mandatoryWarning(source, pos, warningKey)); + public void mandatoryWarning(DiagnosticPosition pos, Warning warningKey, DiagnosticFlag... flags) { + EnumSet flagSet = EnumSet.of(DiagnosticFlag.MANDATORY); + for (DiagnosticFlag flag : flags) + flagSet.add(flag); + report(diags.create(flagSet, source, pos, warningKey)); } /** Provide a non-fatal notification, unless suppressed by the -nowarn option. 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..56e8f227d40c4 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 @@ -115,33 +115,6 @@ public JCDiagnostic error( return diag; } - /** - * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options. - * @param lc The lint category for the diagnostic - * @param source The source of the compilation unit, if any, in which to report the warning. - * @param pos The source position at which to report the warning. - * @param key The key for the localized warning message. - * @param args Fields of the warning message. - * @see MandatoryWarningHandler - */ - public JCDiagnostic mandatoryWarning( - LintCategory lc, - DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { - return mandatoryWarning(source, pos, warningKey(lc, key, args)); - } - - /** - * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options. - * @param source The source of the compilation unit, if any, in which to report the warning. - * @param pos The source position at which to report the warning. - * @param warningKey The key for the localized warning message. - * @see MandatoryWarningHandler - */ - public JCDiagnostic mandatoryWarning( - DiagnosticSource source, DiagnosticPosition pos, Warning warningKey) { - return create(EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, warningKey); - } - /** * Create a warning diagnostic. * @param lc The lint category for the diagnostic @@ -447,6 +420,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, 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..44d893d1fb0e2 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,49 @@ 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(MandatoryWarningAggregator::aggregationNotes) + .flatMap(List::stream) + .forEach(this::report); + aggregators.clear(); + } + + private MandatoryWarningAggregator aggregatorFor(LintCategory lc) { + return switch (lc) { + case PREVIEW -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, Source.instance(context), c)); + case DEPRECATION -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, null, c, "deprecated")); + case REMOVAL, UNCHECKED -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, null, c)); + case null, default -> null; + }; + } /** * Reset the state of this instance. @@ -695,14 +752,19 @@ public void clear() { nsuppressedwarns = 0; while (diagnosticHandler.prev != null) popDiagnosticHandler(diagnosticHandler); + aggregators.values().forEach(MandatoryWarningAggregator::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 +789,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 +810,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 +820,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/MandatoryWarningAggregator.java similarity index 72% 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/MandatoryWarningAggregator.java index 046740ddc3028..b6130d384aa5d 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/MandatoryWarningAggregator.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,9 +42,10 @@ /** - * A handler to process mandatory warnings, setting up a deferred diagnostic + * An aggregator for mandatory 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. + * because the lint category is not enabled or too many warnings have already + * been generated. * *

* Note that the SuppressWarnings annotation can be used to suppress warnings @@ -58,7 +62,7 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -public class MandatoryWarningHandler { +class MandatoryWarningAggregator { /** * The kinds of different deferred diagnostics that might be generated @@ -105,64 +109,51 @@ private enum DeferredDiagnosticKind { /** - * Create a handler for mandatory warnings. + * Create an aggregator for mandatory warnings. * * @param log The log on which to generate any diagnostics * @param source Associated source file, or null for none - * @param verbose Specify whether or not detailed messages about - * individual instances should be given, or whether an aggregate - * message should be generated at the end of the compilation. - * Typically set via -Xlint:option. - * @param enforceMandatory - * True if mandatory warnings and notes are being enforced. * @param 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 MandatoryWarningAggregator(Log log, Source source, LintCategory lc) { + this(log, source, lc, null); } /** - * Create a handler for mandatory warnings. + * Create an aggregator for mandatory warnings. * * @param log The log on which to generate any diagnostics * @param source Associated source file, or null for none - * @param verbose Specify whether or not detailed messages about - * individual instances should be given, or whether an aggregate - * message should be generated at the end of the compilation. - * Typically set via -Xlint:option. - * @param enforceMandatory - * True if mandatory warnings and notes are being enforced. * @param 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 MandatoryWarningAggregator(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 mandatory warning and determine whether to emit it. * - * @param pos source code position - * @param warnKey lint warning + * @param diagnostic the mandatory 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.isMandatory()); + 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 +185,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("compiler", msg, args))); } /** @@ -226,12 +223,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 +259,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 +270,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; From 81670b149864adb092b58d03b38563d45ec93d2a Mon Sep 17 00:00:00 2001 From: "Archie L. Cobbs" Date: Mon, 23 Jun 2025 11:54:34 -0400 Subject: [PATCH 2/6] Apply some review suggestions. --- .../share/classes/com/sun/tools/javac/comp/Check.java | 4 ++-- .../share/classes/com/sun/tools/javac/util/Log.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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 68d1a1125ded0..9eedc7cf2f93a 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 @@ -245,8 +245,8 @@ void warnDeprecated(DiagnosticPosition pos, Symbol sym) { warningKey = LintWarnings.HasBeenDeprecated(sym, sym.location()); } } - Optional.ofNullable(warningKey) - .ifPresent(key -> log.mandatoryWarning(pos, key, DiagnosticFlag.AGGREGATE)); + if (warningKey != null) + log.mandatoryWarning(pos, warningKey, DiagnosticFlag.AGGREGATE); } /** Log a preview warning. 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 44d893d1fb0e2..9a63d779d8506 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 @@ -752,7 +752,7 @@ public void clear() { nsuppressedwarns = 0; while (diagnosticHandler.prev != null) popDiagnosticHandler(diagnosticHandler); - aggregators.values().forEach(MandatoryWarningAggregator::clear); + aggregators.clear(); suppressedDeferredMandatory.clear(); } From 2ebeefc949141288a02da0982a15fe875ba4857b Mon Sep 17 00:00:00 2001 From: "Archie L. Cobbs" Date: Fri, 27 Jun 2025 17:31:00 -0500 Subject: [PATCH 3/6] Add DiagnosticFlag support to compiler.properties and put AGGREGATE there. --- .../propertiesparser/gen/ClassGenerator.java | 15 ++- .../propertiesparser/parser/Message.java | 7 +- .../propertiesparser/parser/MessageLine.java | 17 +++- .../resources/templates.properties | 21 +++- .../com/sun/tools/javac/code/Preview.java | 3 +- .../com/sun/tools/javac/comp/Check.java | 6 +- .../tools/javac/resources/compiler.properties | 17 ++++ .../com/sun/tools/javac/util/AbstractLog.java | 31 ++---- .../sun/tools/javac/util/JCDiagnostic.java | 99 ++++++++++++++----- .../classes/com/sun/tools/javac/util/Log.java | 3 +- .../util/MandatoryWarningAggregator.java | 2 +- 11 files changed, 154 insertions(+), 67 deletions(-) diff --git a/make/langtools/tools/propertiesparser/gen/ClassGenerator.java b/make/langtools/tools/propertiesparser/gen/ClassGenerator.java index e869d60bbc569..10bc274e14159 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 @@ -93,7 +93,8 @@ 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("diagnostic.flags"); /** stub key (as it appears in the property file) */ String key; @@ -259,17 +260,25 @@ 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 + "\"") + .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.format(diagnosticFlags) : "null", "\"" + 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.format(diagnosticFlags) : "null", StubKind.LINT_CATEGORY.format("\"" + lintCategory + "\""), "\"" + keyParts[0] + "\"", "\"" + Stream.of(keyParts).skip(2).collect(Collectors.joining(".")) + "\"", @@ -287,11 +296,13 @@ 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.format(diagnosticFlags) : "null", "\"" + 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.format(diagnosticFlags) : "null", 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..8488124da2254 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,9 @@ toplevel.decl=\ import com.sun.tools.javac.util.JCDiagnostic.Fragment;\n\ import com.sun.tools.javac.code.Lint.LintCategory;\n\ \n\ + import java.util.Locale;\n\ + import java.util.stream.Stream;\n\ + \n\ public class {2} '{'\n\ {3}\n\ '}'\n @@ -58,22 +62,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 +88,10 @@ suppress.warnings=\ lint.category=\ LintCategory.get({0}).get() +diagnostic.flags=\n\ + ' 'Stream.of({0})\n\ + ' '.map(s -> s.replace(''-'', ''_''))\n\ + ' '.map(s -> s.toUpperCase(Locale.ROOT))\n\ + ' '.map(DiagnosticFlag::valueOf)\n\ + ' '.toArray(DiagnosticFlag[]::new) + 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 0b06863cd962f..4f7a84844fbde 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 @@ -175,8 +175,7 @@ public void warnPreview(DiagnosticPosition pos, Feature feature) { log.mandatoryWarning(pos, feature.isPlural() ? LintWarnings.PreviewFeatureUsePlural(feature.nameFragment()) : - LintWarnings.PreviewFeatureUse(feature.nameFragment()), - DiagnosticFlag.AGGREGATE); + LintWarnings.PreviewFeatureUse(feature.nameFragment())); } /** 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 9eedc7cf2f93a..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 @@ -246,7 +246,7 @@ void warnDeprecated(DiagnosticPosition pos, Symbol sym) { } } if (warningKey != null) - log.mandatoryWarning(pos, warningKey, DiagnosticFlag.AGGREGATE); + log.mandatoryWarning(pos, warningKey); } /** Log a preview warning. @@ -255,7 +255,7 @@ void warnDeprecated(DiagnosticPosition pos, Symbol sym) { */ public void warnPreviewAPI(DiagnosticPosition pos, LintWarning warnKey) { if (!importSuppression && !lint.isSuppressed(LintCategory.PREVIEW)) - log.mandatoryWarning(pos, warnKey, DiagnosticFlag.AGGREGATE); + log.mandatoryWarning(pos, warnKey); } /** Log a preview warning. @@ -272,7 +272,7 @@ public void warnRestrictedAPI(DiagnosticPosition pos, Symbol sym) { */ public void warnUnchecked(DiagnosticPosition pos, LintWarning warnKey) { if (!lint.isSuppressed(LintCategory.UNCHECKED)) - log.mandatoryWarning(pos, warnKey, DiagnosticFlag.AGGREGATE); + log.mandatoryWarning(pos, warnKey); } /** Report a failure to complete a class. 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..e6c57169f0fdb 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} @@ -3282,11 +3296,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 +4265,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/AbstractLog.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java index d7d328ddae4a3..59730448bf53a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, 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,7 +25,6 @@ package com.sun.tools.javac.util; -import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import javax.tools.JavaFileObject; @@ -160,45 +159,35 @@ public void error(DiagnosticFlag flag, int pos, Error errorKey) { * maximum number of warnings has been reached. * * @param warningKey The key for the localized warning message. - * @param flags Any additional flags required */ - public void warning(Warning warningKey, DiagnosticFlag... flags) { - warning(null, warningKey, flags); + public void warning(Warning warningKey) { + report(diags.warning(source, null, warningKey)); } /** Report a warning, unless suppressed by the -nowarn option or the * maximum number of warnings has been reached. * @param pos The source position at which to report the warning. * @param warningKey The key for the localized warning message. - * @param flags Any additional flags required */ - public void warning(int pos, Warning warningKey, DiagnosticFlag... flags) { - warning(wrap(pos), warningKey, flags); + public void warning(DiagnosticPosition pos, Warning warningKey) { + report(diags.warning(source, pos, warningKey)); } /** Report a warning, unless suppressed by the -nowarn option or the * maximum number of warnings has been reached. * @param pos The source position at which to report the warning. * @param warningKey The key for the localized warning message. - * @param flags Any additional flags required */ - public void warning(DiagnosticPosition pos, Warning warningKey, DiagnosticFlag... flags) { - EnumSet flagSet = EnumSet.noneOf(DiagnosticFlag.class); - for (DiagnosticFlag flag : flags) - flagSet.add(flag); - report(diags.create(flagSet, source, pos, warningKey)); + public void warning(int pos, Warning warningKey) { + report(diags.warning(source, wrap(pos), warningKey)); } - /** Report a mandatory warning. + /** Report a warning. * @param pos The source position at which to report the warning. * @param warningKey The key for the localized warning message. - * @param flags Any additional flags required */ - public void mandatoryWarning(DiagnosticPosition pos, Warning warningKey, DiagnosticFlag... flags) { - EnumSet flagSet = EnumSet.of(DiagnosticFlag.MANDATORY); - for (DiagnosticFlag flag : flags) - flagSet.add(flag); - report(diags.create(flagSet, source, pos, warningKey)); + public void mandatoryWarning(DiagnosticPosition pos, Warning warningKey) { + report(diags.mandatoryWarning(source, pos, warningKey)); } /** Provide a non-fatal notification, unless suppressed by the -nowarn option. 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 56e8f227d40c4..c7a889f913298 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; @@ -115,6 +116,33 @@ public JCDiagnostic error( return diag; } + /** + * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options. + * @param lc The lint category for the diagnostic + * @param source The source of the compilation unit, if any, in which to report the warning. + * @param pos The source position at which to report the warning. + * @param key The key for the localized warning message. + * @param args Fields of the warning message. + * @see MandatoryWarningHandler + */ + public JCDiagnostic mandatoryWarning( + LintCategory lc, + DiagnosticSource source, DiagnosticPosition pos, String key, Object... args) { + return mandatoryWarning(source, pos, warningKey(lc, key, args)); + } + + /** + * Create a warning diagnostic that will not be hidden by the -nowarn or -Xlint:none options. + * @param source The source of the compilation unit, if any, in which to report the warning. + * @param pos The source position at which to report the warning. + * @param warningKey The key for the localized warning message. + * @see MandatoryWarningHandler + */ + public JCDiagnostic mandatoryWarning( + DiagnosticSource source, DiagnosticPosition pos, Warning warningKey) { + return create(EnumSet.of(DiagnosticFlag.MANDATORY), source, pos, warningKey); + } + /** * Create a warning diagnostic. * @param lc The lint category for the diagnostic @@ -210,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)); } /** @@ -225,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); } /** @@ -252,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)); } /** @@ -276,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; @@ -287,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); } } @@ -324,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, @@ -479,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 (if not null). */ + DiagnosticFlag[] flags; + /** The diagnostic prefix (i.e. 'javac'); used to compute full resource key. */ String prefix; @@ -489,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, DiagnosticFlag[] flags, String prefix, String code, Object... args) { this.type = type; + this.flags = flags; this.prefix = prefix; this.code = code; this.args = args; @@ -506,22 +540,23 @@ 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, 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, 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; @@ -545,14 +580,18 @@ public Object[] getArgs() { public void setArgs(Object[] args) { this.args = args; } + + public boolean hasFlag(DiagnosticFlag flag) { + return flags != null && Arrays.asList(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(DiagnosticFlag[] flags, String prefix, String key, Object... args) { + super(DiagnosticType.ERROR, flags, prefix, key, args); } } @@ -560,8 +599,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(DiagnosticFlag[] flags, String prefix, String key, Object... args) { + super(DiagnosticType.WARNING, flags, prefix, key, args); } } @@ -571,8 +610,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(DiagnosticFlag[] flags, LintCategory category, String prefix, String key, Object... args) { + super(flags, prefix, key, args); this.category = category; } @@ -585,8 +624,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(DiagnosticFlag[] flags, String prefix, String key, Object... args) { + super(DiagnosticType.NOTE, flags, prefix, key, args); } } @@ -594,8 +633,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(DiagnosticFlag[] flags, String prefix, String key, Object... args) { + super(DiagnosticType.FRAGMENT, flags, prefix, key, args); } } @@ -640,6 +679,12 @@ protected JCDiagnostic(DiagnosticFormatter formatter, this.source = source; this.position = pos; this.rewriter = rewriter; + + if (diagnosticInfo.flags != null) { + for (DiagnosticFlag flag : diagnosticInfo.flags) { + this.flags.add(flag); + } + } } /** 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 9a63d779d8506..1825a897d7f31 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 @@ -735,8 +735,7 @@ private MandatoryWarningAggregator aggregatorFor(LintCategory lc) { return switch (lc) { case PREVIEW -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, Source.instance(context), c)); case DEPRECATION -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, null, c, "deprecated")); - case REMOVAL, UNCHECKED -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, null, c)); - case null, default -> null; + default -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, null, c)); }; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningAggregator.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningAggregator.java index b6130d384aa5d..b5da48f9183dc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningAggregator.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningAggregator.java @@ -214,7 +214,7 @@ public List aggregationNotes() { } private void addNote(List list, JavaFileObject file, String msg, Object... args) { - list.add(log.diags.mandatoryNote(log.getSource(file), new Note("compiler", msg, args))); + list.add(log.diags.mandatoryNote(log.getSource(file), new Note(null, "compiler", msg, args))); } /** From 95b368fb41185cd6ced98c8c8a875ce86fa81682 Mon Sep 17 00:00:00 2001 From: "Archie L. Cobbs" Date: Fri, 27 Jun 2025 17:31:20 -0500 Subject: [PATCH 4/6] Move (most) SOURCE_LEVEL flags into compiler.properties. --- .../com/sun/tools/javac/code/Preview.java | 5 ++--- .../com/sun/tools/javac/comp/Attr.java | 7 ++----- .../sun/tools/javac/parser/JavaTokenizer.java | 19 +++---------------- .../sun/tools/javac/parser/JavacParser.java | 4 ++-- .../tools/javac/resources/compiler.properties | 4 ++++ 5 files changed, 13 insertions(+), 26 deletions(-) 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 4f7a84844fbde..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 @@ -34,7 +34,6 @@ import com.sun.tools.javac.resources.CompilerProperties.Warnings; import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.JCDiagnostic.Error; import com.sun.tools.javac.util.JCDiagnostic.LintWarning; @@ -265,10 +264,10 @@ public boolean declaredUsingPreviewFeature(Symbol sym) { public void checkSourceLevel(DiagnosticPosition pos, Feature feature) { if (isPreview(feature) && !isEnabled()) { //preview feature without --preview flag, error - log.error(DiagnosticFlag.SOURCE_LEVEL, pos, disabledError(feature)); + log.error(pos, disabledError(feature)); } else { if (!feature.allowedInSource(source)) { - log.error(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/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 e6c57169f0fdb..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 @@ -3260,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}) @@ -3280,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}) From 8d822b11197efd5bf29358a8ef0caedd203adcfb Mon Sep 17 00:00:00 2001 From: "Archie L. Cobbs" Date: Thu, 3 Jul 2025 09:31:40 -0500 Subject: [PATCH 5/6] Remove assumptions about mandatoryness from the MandatoryWarningAggregator. --- .../classes/com/sun/tools/javac/util/Log.java | 12 ++++----- ...Aggregator.java => WarningAggregator.java} | 27 +++++++------------ 2 files changed, 15 insertions(+), 24 deletions(-) rename src/jdk.compiler/share/classes/com/sun/tools/javac/util/{MandatoryWarningAggregator.java => WarningAggregator.java} (90%) 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 1825a897d7f31..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 @@ -707,7 +707,7 @@ private Lint rootLint() { // Mandatory Warnings - private final EnumMap aggregators = new EnumMap<>(LintCategory.class); + private final EnumMap aggregators = new EnumMap<>(LintCategory.class); private final EnumSet suppressedDeferredMandatory = EnumSet.noneOf(LintCategory.class); @@ -725,17 +725,17 @@ public void reportOutstandingNotes() { aggregators.entrySet().stream() .filter(entry -> !suppressedDeferredMandatory.contains(entry.getKey())) .map(Map.Entry::getValue) - .map(MandatoryWarningAggregator::aggregationNotes) + .map(WarningAggregator::aggregationNotes) .flatMap(List::stream) .forEach(this::report); aggregators.clear(); } - private MandatoryWarningAggregator aggregatorFor(LintCategory lc) { + private WarningAggregator aggregatorFor(LintCategory lc) { return switch (lc) { - case PREVIEW -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, Source.instance(context), c)); - case DEPRECATION -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, null, c, "deprecated")); - default -> aggregators.computeIfAbsent(lc, c -> new MandatoryWarningAggregator(this, null, c)); + 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)); }; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningAggregator.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/WarningAggregator.java similarity index 90% rename from src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningAggregator.java rename to src/jdk.compiler/share/classes/com/sun/tools/javac/util/WarningAggregator.java index b5da48f9183dc..2bb8d2e2754f7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/MandatoryWarningAggregator.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/WarningAggregator.java @@ -42,19 +42,12 @@ /** - * An aggregator for 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 the lint category is not enabled or 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. - * - *

* All warnings must be in the same {@link LintCategory} provided to the constructor. * *

This is NOT part of any supported API. @@ -62,12 +55,11 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -class MandatoryWarningAggregator { +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. */ @@ -109,18 +101,18 @@ private enum DeferredDiagnosticKind { /** - * Create an aggregator 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 lc The lint category for all warnings */ - public MandatoryWarningAggregator(Log log, Source source, LintCategory lc) { + public WarningAggregator(Log log, Source source, LintCategory lc) { this(log, source, lc, null); } /** - * Create an aggregator 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 @@ -128,7 +120,7 @@ public MandatoryWarningAggregator(Log log, Source source, LintCategory lc) { * @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 MandatoryWarningAggregator(Log log, Source source, LintCategory lc, String prefix) { + public WarningAggregator(Log log, Source source, LintCategory lc, String prefix) { this.log = log; this.source = source; this.prefix = prefix != null ? prefix : lc.option; @@ -136,14 +128,13 @@ public MandatoryWarningAggregator(Log log, Source source, LintCategory lc, Strin } /** - * Aggregate a mandatory warning and determine whether to emit it. + * Aggregate a warning and determine whether to emit it. * - * @param diagnostic the mandatory 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 boolean aggregate(JCDiagnostic diagnostic, boolean verbose) { - Assert.check(diagnostic.isMandatory()); Assert.check(diagnostic.getLintCategory() == lintCategory); JavaFileObject currentSource = log.currentSourceFile(); if (verbose) { From 2b16d65758ba90c6b7acaa55b64828d2f40e1f15 Mon Sep 17 00:00:00 2001 From: "Archie L. Cobbs" Date: Thu, 3 Jul 2025 10:03:15 -0500 Subject: [PATCH 6/6] Address review suggestions. --- .../propertiesparser/gen/ClassGenerator.java | 23 ++++++++++---- .../resources/templates.properties | 16 +++++----- .../sun/tools/javac/util/JCDiagnostic.java | 31 +++++++++---------- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/make/langtools/tools/propertiesparser/gen/ClassGenerator.java b/make/langtools/tools/propertiesparser/gen/ClassGenerator.java index 10bc274e14159..247537b467699 100644 --- a/make/langtools/tools/propertiesparser/gen/ClassGenerator.java +++ b/make/langtools/tools/propertiesparser/gen/ClassGenerator.java @@ -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; @@ -94,7 +95,8 @@ enum StubKind { WILDCARDS_EXTENDS("wildcards.extends"), SUPPRESS_WARNINGS("suppress.warnings"), LINT_CATEGORY("lint.category"), - DIAGNOSTIC_FLAGS("diagnostic.flags"); + 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; @@ -264,7 +266,8 @@ List generateFactoryMethodsAndFields(FactoryKind k, String key, Message .filter(MessageLine::isDiagnosticFlags) .map(MessageLine::diagnosticFlags) .flatMap(Stream::of) - .map(s -> "\"" + s + "\"") + .map(s -> s.replace('-', '_')) + .map(s -> s.toUpperCase(Locale.ROOT)) .collect(Collectors.joining(", ")); String factoryName = factoryName(key); if (msgInfo.getTypes().isEmpty()) { @@ -272,13 +275,17 @@ List generateFactoryMethodsAndFields(FactoryKind k, String key, Message String factoryField; if (lintCategory == null) { factoryField = StubKind.FACTORY_FIELD.format(k.keyClazz, factoryName, - !diagnosticFlags.isEmpty() ? StubKind.DIAGNOSTIC_FLAGS.format(diagnosticFlags) : "null", + 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.format(diagnosticFlags) : "null", + 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(".")) + "\"", @@ -296,13 +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.format(diagnosticFlags) : "null", + 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.format(diagnosticFlags) : "null", + 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/resources/templates.properties b/make/langtools/tools/propertiesparser/resources/templates.properties index 8488124da2254..81a9be2552c26 100644 --- a/make/langtools/tools/propertiesparser/resources/templates.properties +++ b/make/langtools/tools/propertiesparser/resources/templates.properties @@ -35,8 +35,9 @@ toplevel.decl=\ import com.sun.tools.javac.util.JCDiagnostic.Fragment;\n\ import com.sun.tools.javac.code.Lint.LintCategory;\n\ \n\ - import java.util.Locale;\n\ - import java.util.stream.Stream;\n\ + import java.util.EnumSet;\n\ + \n\ + import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*;\n\ \n\ public class {2} '{'\n\ {3}\n\ @@ -88,10 +89,9 @@ suppress.warnings=\ lint.category=\ LintCategory.get({0}).get() -diagnostic.flags=\n\ - ' 'Stream.of({0})\n\ - ' '.map(s -> s.replace(''-'', ''_''))\n\ - ' '.map(s -> s.toUpperCase(Locale.ROOT))\n\ - ' '.map(DiagnosticFlag::valueOf)\n\ - ' '.toArray(DiagnosticFlag[]::new) +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/util/JCDiagnostic.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java index c7a889f913298..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 @@ -509,8 +509,8 @@ 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 (if not null). */ - DiagnosticFlag[] flags; + /** 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; @@ -522,9 +522,9 @@ public abstract static class DiagnosticInfo { /** The diagnostic arguments. */ Object[] args; - private DiagnosticInfo(DiagnosticType type, DiagnosticFlag[] flags, String prefix, String code, Object... args) { + private DiagnosticInfo(DiagnosticType type, Set flags, String prefix, String code, Object... args) { this.type = type; - this.flags = flags; + this.flags = flags != null ? flags : EnumSet.noneOf(DiagnosticFlag.class); this.prefix = prefix; this.code = code; this.args = args; @@ -540,11 +540,12 @@ public String key() { /** * Static factory method; build a custom diagnostic key using given kind, prefix, code and args. */ - public static DiagnosticInfo of(DiagnosticType type, DiagnosticFlag[] flags, String prefix, String code, Object... 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, DiagnosticFlag[] flags, + public static DiagnosticInfo of(DiagnosticType type, Set flags, LintCategory lc, String prefix, String code, Object... args) { switch (type) { case ERROR: @@ -582,7 +583,7 @@ public void setArgs(Object[] args) { } public boolean hasFlag(DiagnosticFlag flag) { - return flags != null && Arrays.asList(flags).contains(flag); + return flags.contains(flag); } } @@ -590,7 +591,7 @@ public boolean hasFlag(DiagnosticFlag flag) { * Class representing error diagnostic keys. */ public static final class Error extends DiagnosticInfo { - public Error(DiagnosticFlag[] flags, String prefix, String key, Object... args) { + public Error(Set flags, String prefix, String key, Object... args) { super(DiagnosticType.ERROR, flags, prefix, key, args); } } @@ -599,7 +600,7 @@ public Error(DiagnosticFlag[] flags, String prefix, String key, Object... args) * Class representing warning diagnostic keys. */ public static sealed class Warning extends DiagnosticInfo { - public Warning(DiagnosticFlag[] flags, String prefix, String key, Object... args) { + public Warning(Set flags, String prefix, String key, Object... args) { super(DiagnosticType.WARNING, flags, prefix, key, args); } } @@ -610,7 +611,7 @@ public Warning(DiagnosticFlag[] flags, String prefix, String key, Object... args public static final class LintWarning extends Warning { final LintCategory category; - public LintWarning(DiagnosticFlag[] flags, LintCategory category, String prefix, String key, Object... args) { + public LintWarning(Set flags, LintCategory category, String prefix, String key, Object... args) { super(flags, prefix, key, args); this.category = category; } @@ -624,7 +625,7 @@ public LintCategory getLintCategory() { * Class representing note diagnostic keys. */ public static final class Note extends DiagnosticInfo { - public Note(DiagnosticFlag[] flags, String prefix, String key, Object... args) { + public Note(Set flags, String prefix, String key, Object... args) { super(DiagnosticType.NOTE, flags, prefix, key, args); } } @@ -633,7 +634,7 @@ public Note(DiagnosticFlag[] flags, String prefix, String key, Object... args) { * Class representing fragment diagnostic keys. */ public static final class Fragment extends DiagnosticInfo { - public Fragment(DiagnosticFlag[] flags, String prefix, String key, Object... args) { + public Fragment(Set flags, String prefix, String key, Object... args) { super(DiagnosticType.FRAGMENT, flags, prefix, key, args); } } @@ -680,11 +681,7 @@ protected JCDiagnostic(DiagnosticFormatter formatter, this.position = pos; this.rewriter = rewriter; - if (diagnosticInfo.flags != null) { - for (DiagnosticFlag flag : diagnosticInfo.flags) { - this.flags.add(flag); - } - } + this.flags.addAll(diagnosticInfo.flags); } /**