8382368: Warning that @Deprecated "has no effect" is suppressed by @Deprecated

Reviewed-by: liach
This commit is contained in:
Archie Cobbs 2026-04-19 02:08:28 +00:00
parent 0dd0108c1a
commit d71f070ce6
6 changed files with 81 additions and 48 deletions

View File

@ -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<LintCategory> 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<LintCategory> values;
private EnumSet<LintCategory> suppressedValues;
private boolean withinDeprecated;
private static final Map<String, LintCategory> 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.
*
* <p>
* 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.
*
* <p>
* 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<LintCategory> suppressionsFrom(Symbol symbol) {
EnumSet<LintCategory> 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

View File

@ -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

View File

@ -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<JavaFileObject> {
* 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,

View File

@ -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);

View File

@ -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
}
}

View File

@ -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