From d71f070ce66081013eff2fb91d9e98403312903e Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Sun, 19 Apr 2026 02:08:28 +0000 Subject: [PATCH] 8382368: Warning that @Deprecated "has no effect" is suppressed by @Deprecated Reviewed-by: liach --- .../com/sun/tools/javac/code/Lint.java | 90 +++++++++++-------- .../tools/javac/resources/compiler.properties | 2 +- .../sun/tools/javac/util/JCDiagnostic.java | 6 +- .../classes/com/sun/tools/javac/util/Log.java | 14 +-- .../javac/warnings/DeprecatedNoEffect.java | 14 +++ .../javac/warnings/DeprecatedNoEffect.out | 3 + 6 files changed, 81 insertions(+), 48 deletions(-) create mode 100644 test/langtools/tools/javac/warnings/DeprecatedNoEffect.java create mode 100644 test/langtools/tools/javac/warnings/DeprecatedNoEffect.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index 773c573c201..776fd544bfb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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 @@ -37,11 +37,16 @@ import java.util.Set; import java.util.stream.Stream; import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Options; +import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.DEFAULT_ENABLED; +import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.DEPRECATION_SENSITIVE; + /** * A class for handling -Xlint suboptions and @SuppressWarnings. * @@ -76,35 +81,20 @@ public class Lint { */ public Lint augment(Symbol sym) { EnumSet suppressions = suppressionsFrom(sym); - if (!suppressions.isEmpty()) { + boolean symWithinDeprecated = withinDeprecated || isDeprecatedDeclaration(sym); + if (!suppressions.isEmpty() || symWithinDeprecated != withinDeprecated) { Lint lint = new Lint(this); lint.values.removeAll(suppressions); lint.suppressedValues.addAll(suppressions); + lint.withinDeprecated = symWithinDeprecated; return lint; } return this; } - /** - * Returns a new Lint that has the given LintCategorys enabled. - * @param lc one or more categories to be enabled - */ - public Lint enable(LintCategory... lc) { - Lint l = new Lint(this); - l.values.addAll(Arrays.asList(lc)); - l.suppressedValues.removeAll(Arrays.asList(lc)); - return l; - } - - /** - * Returns a new Lint that has the given LintCategorys suppressed. - * @param lc one or more categories to be suppressed - */ - public Lint suppress(LintCategory... lc) { - Lint l = new Lint(this); - l.values.removeAll(Arrays.asList(lc)); - l.suppressedValues.addAll(Arrays.asList(lc)); - return l; + // Does sym's declaration have a (non-useless) @Deprecated annotation? + public static boolean isDeprecatedDeclaration(Symbol sym) { + return sym.isDeprecated() && sym.isDeprecatableViaAnnotation(); } private final Context context; @@ -115,9 +105,12 @@ public class Lint { private Symtab syms; private Names names; - // Invariant: it's never the case that a category is in both "values" and "suppressedValues" + // Invariants: + // - It's never the case that a category is in both "values" and "suppressedValues" + // - All categories in "suppressedValues" have annotationSuppression = true private EnumSet values; private EnumSet suppressedValues; + private boolean withinDeprecated; private static final Map map = new LinkedHashMap<>(40); @@ -129,7 +122,7 @@ public class Lint { log = Log.instance(context); } - // Instantiate a non-root ("symbol scoped") instance + // Copy constructor - used to instantiate a non-root ("symbol scoped") instances protected Lint(Lint other) { other.initializeRootIfNeeded(); this.context = other.context; @@ -139,6 +132,7 @@ public class Lint { this.names = other.names; this.values = other.values.clone(); this.suppressedValues = other.suppressedValues.clone(); + this.withinDeprecated = other.withinDeprecated; } // Process command line options on demand to allow use of root Lint early during startup @@ -169,7 +163,7 @@ public class Lint { @Override public String toString() { initializeRootIfNeeded(); - return "Lint:[enable" + values + ",suppress" + suppressedValues + "]"; + return "Lint:[enable" + values + ",suppress" + suppressedValues + ",deprecated=" + withinDeprecated + "]"; } /** @@ -443,6 +437,34 @@ public class Lint { public final boolean enabledByDefault; } + /** + * Determine if the given diagnostic should be emitted given the state of this instance. + */ + public boolean shouldEmit(JCDiagnostic diag) { + + // Check category + LintCategory category = diag.getLintCategory(); + if (category == null) + return true; + + // Certain warnings within @Deprecated declarations are automatically suppressed (JLS 9.6.4.6) + if (withinDeprecated && diag.isFlagSet(DEPRECATION_SENSITIVE)) { + Assert.check(diag.isFlagSet(DEFAULT_ENABLED) && category.annotationSuppression); + return false; + } + + // If the warning is not enabled by default, then emit only when its lint category is explicitly enabled + if (!diag.isFlagSet(DEFAULT_ENABLED)) + return isEnabled(category); + + // If the lint category doesn't support @SuppressWarnings, then we just check the -Xlint:category flag + if (!category.annotationSuppression) + return !options.isDisabled(Option.XLINT, category); + + // Check whether the lint category is currently suppressed + return !isSuppressed(category); + } + /** * Checks if a warning category is enabled. A warning category may be enabled * on the command line, or by default, and can be temporarily disabled with @@ -454,10 +476,11 @@ public class Lint { } /** - * Checks is a warning category has been specifically suppressed, by means - * of the SuppressWarnings annotation, or, in the case of the deprecated - * category, whether it has been implicitly suppressed by virtue of the - * current entity being itself deprecated. + * Check if a warning category has been specifically suppressed by means of @SuppressWarnings. + * + *

+ * Always returns false for categories that are not suppressible by the annotation, even + * if they (uselessly) happen to appear in one. */ public boolean isSuppressed(LintCategory lc) { initializeRootIfNeeded(); @@ -468,17 +491,14 @@ public class Lint { * Obtain the set of recognized lint warning categories suppressed at the given symbol's declaration. * *

- * This set can be non-empty only if the symbol is annotated with either - * @SuppressWarnings or @Deprecated. + * This set can be non-empty only if the symbol is annotated with @SuppressWarnings, and only categories + * for which {@code annotationSuppression} is true are included. * * @param symbol symbol corresponding to a possibly-annotated declaration * @return new warning suppressions applied to sym */ public EnumSet suppressionsFrom(Symbol symbol) { - EnumSet suppressions = suppressionsFrom(symbol.getDeclarationAttributes().stream()); - if (symbol.isDeprecated() && symbol.isDeprecatableViaAnnotation()) - suppressions.add(LintCategory.DEPRECATION); - return suppressions; + return suppressionsFrom(symbol.getDeclarationAttributes().stream()); } // Find the @SuppressWarnings annotation in the given stream and extract the recognized suppressions 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 58a5333ce4c..a2bfb9c7201 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 @@ -1960,7 +1960,7 @@ compiler.warn.incubating.modules=\ # 0: symbol, 1: symbol # lint: deprecation -# flags: aggregate, mandatory, default-enabled +# flags: aggregate, mandatory, default-enabled, deprecation-sensitive compiler.warn.has.been.deprecated=\ {0} in {1} has been deprecated 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 328183c0cb3..aed42f7b2b2 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -436,6 +436,10 @@ public class JCDiagnostic implements Diagnostic { * is not explicitly enabled, as long as it is not explicitly suppressed. */ DEFAULT_ENABLED, + /** Flag for warnings that are automatically suppressed when they occur inside + * a declaration that is itself annotated as @Deprecated. See JLS 9.6.4.6. + */ + DEPRECATION_SENSITIVE, /** Flags mandatory warnings that should pass through a mandatory warning aggregator. */ AGGREGATE, 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 b061d2283a0..99f71e87df1 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, 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 @@ -174,16 +174,8 @@ public class Log extends AbstractLog { } // Apply the lint configuration (if any) and discard the warning if it gets filtered out - if (lint != null) { - LintCategory category = diag.getLintCategory(); - boolean emit = !diag.isFlagSet(DEFAULT_ENABLED) ? // is the warning not enabled by default? - lint.isEnabled(category) : // then emit if the category is enabled - category.annotationSuppression ? // else emit if the category is not suppressed, where - !lint.isSuppressed(category) : // ...suppression happens via @SuppressWarnings - !options.isDisabled(Option.XLINT, category); // ...suppression happens via -Xlint:-category - if (!emit) - return; - } + if (lint != null && !lint.shouldEmit(diag)) + return; // Proceed reportReady(diag); diff --git a/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java new file mode 100644 index 00000000000..b2c8a10c0ac --- /dev/null +++ b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java @@ -0,0 +1,14 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8382368 + * @compile/ref=DeprecatedNoEffect.out -Xlint:deprecation -XDrawDiagnostics DeprecatedNoEffect.java + */ +public class DeprecatedNoEffect { + void m1() { + @Deprecated int i1; // there should be a "has no effect" warning here + } + @Deprecated + void m2() { + @Deprecated int i2; // there should be a "has no effect" warning here also + } +} diff --git a/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out new file mode 100644 index 00000000000..55003e62fb8 --- /dev/null +++ b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out @@ -0,0 +1,3 @@ +DeprecatedNoEffect.java:8:21: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable +DeprecatedNoEffect.java:12:21: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable +2 warnings