8155591: Misleading warning when not overriding close method in interface extending AutoCloseable

Reviewed-by: jlahoda
This commit is contained in:
Archie Cobbs 2025-11-06 15:28:01 +00:00
parent 2d924ad358
commit a5864582da
6 changed files with 306 additions and 6 deletions

View File

@ -1982,7 +1982,7 @@ public class Attr extends JCTree.Visitor {
twrResult.check(resource, resource.type);
//check that resource type cannot throw InterruptedException
checkAutoCloseable(resource.pos(), localEnv, resource.type);
checkAutoCloseable(localEnv, resource, true);
VarSymbol var = ((JCVariableDecl) resource).sym;
@ -2031,7 +2031,9 @@ public class Attr extends JCTree.Visitor {
}
}
void checkAutoCloseable(DiagnosticPosition pos, Env<AttrContext> env, Type resource) {
void checkAutoCloseable(Env<AttrContext> env, JCTree tree, boolean useSite) {
DiagnosticPosition pos = tree.pos();
Type resource = tree.type;
if (!resource.isErroneous() &&
types.asSuper(resource, syms.autoCloseableType.tsym) != null &&
!types.isSameType(resource, syms.autoCloseableType)) { // Don't emit warning for AutoCloseable itself
@ -2049,9 +2051,15 @@ public class Attr extends JCTree.Visitor {
log.popDiagnosticHandler(discardHandler);
}
if (close.kind == MTH &&
close.overrides(syms.autoCloseableClose, resource.tsym, types, true) &&
(useSite || close.owner != syms.autoCloseableType.tsym) &&
((MethodSymbol)close).binaryOverrides(syms.autoCloseableClose, resource.tsym, types) &&
chk.isHandled(syms.interruptedExceptionType, types.memberType(resource, close).getThrownTypes())) {
log.warning(pos, LintWarnings.TryResourceThrowsInterruptedExc(resource));
if (!useSite && close.owner == resource.tsym) {
log.warning(TreeInfo.diagnosticPositionFor(close, tree),
LintWarnings.TryResourceCanThrowInterruptedExc(resource));
} else {
log.warning(pos, LintWarnings.TryResourceThrowsInterruptedExc(resource));
}
}
}
}
@ -5649,7 +5657,7 @@ public class Attr extends JCTree.Visitor {
chk.checkImplementations(tree);
//check that a resource implementing AutoCloseable cannot throw InterruptedException
checkAutoCloseable(tree.pos(), env, c.type);
checkAutoCloseable(env, tree, false);
for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
// Attribute declaration

View File

@ -2368,6 +2368,11 @@ compiler.warn.try.resource.not.referenced=\
compiler.warn.try.resource.throws.interrupted.exc=\
auto-closeable resource {0} has a member method close() that could throw InterruptedException
# 0: type
# lint: try
compiler.warn.try.resource.can.throw.interrupted.exc=\
close() method can throw InterruptedException in auto-closeable class {0}
# lint: unchecked
compiler.warn.unchecked.assign=\
unchecked assignment: {0} to {1}

View File

@ -228,7 +228,8 @@ public class InterruptedExceptionTest {
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
if (diagnostic.getKind() == Diagnostic.Kind.WARNING &&
diagnostic.getCode().contains("try.resource.throws.interrupted.exc")) {
(diagnostic.getCode().contains("try.resource.throws.interrupted.exc") ||
diagnostic.getCode().contains("try.resource.can.throw.interrupted.exc"))) {
tryWarnFound++;
}
}

View File

@ -0,0 +1,256 @@
/*
* @test /nodynamiccopyright/
* @bug 8155591
* @summary Verify cases where no AutoCloseable InterruptedException warning should be generated
* @compile/ref=InterruptedExceptionTest2.out -XDrawDiagnostics -Xlint:try InterruptedExceptionTest2.java
*/
import java.util.function.Supplier;
// Here's an interface and a class that we can inherit declaring offending close() methods
interface HasClose {
void close() throws Exception;
}
class WithConcreteClose {
public void close() throws Exception { }
}
abstract class WithAbstractClose {
public abstract void close() throws Exception;
}
// Interface declaration tests
interface InterruptedExceptionTest_I1 extends AutoCloseable {
}
interface InterruptedExceptionTest_I2 extends AutoCloseable {
@Override void close();
}
interface InterruptedExceptionTest_I3 extends AutoCloseable {
@Override void close() throws InterruptedException; // warning here
}
interface InterruptedExceptionTest_I4 extends AutoCloseable {
@Override void close() throws Exception; // warning here
}
interface InterruptedExceptionTest_I5 extends AutoCloseable {
@Override default void close() { }
}
interface InterruptedExceptionTest_I6 extends AutoCloseable {
@Override default void close() throws InterruptedException { } // warning here
}
interface InterruptedExceptionTest_I7 extends AutoCloseable {
@Override default void close() throws Exception { } // warning here
}
interface InterruptedExceptionTest_I8 extends HasClose, AutoCloseable {
}
interface InterruptedExceptionTest_I9 extends HasClose, AutoCloseable {
@Override void close();
}
// Abstract class declaration tests
abstract class InterruptedExceptionTest_C1 implements AutoCloseable {
}
abstract class InterruptedExceptionTest_C2 implements AutoCloseable {
@Override public abstract void close();
}
abstract class InterruptedExceptionTest_C3 implements AutoCloseable {
@Override public abstract void close() throws InterruptedException; // warning here
}
abstract class InterruptedExceptionTest_C4 implements AutoCloseable {
@Override public abstract void close() throws Exception; // warning here
}
abstract class InterruptedExceptionTest_C5 implements AutoCloseable {
@Override public void close() { }
}
abstract class InterruptedExceptionTest_C6 implements AutoCloseable {
@Override public void close() throws InterruptedException { } // warning here
}
abstract class InterruptedExceptionTest_C7 implements AutoCloseable {
@Override public void close() throws Exception { } // warning here
}
abstract class InterruptedExceptionTest_C8 implements HasClose, AutoCloseable {
}
abstract class InterruptedExceptionTest_C9 implements HasClose, AutoCloseable {
@Override public void close() { }
}
abstract class InterruptedExceptionTest_C10 extends WithConcreteClose implements AutoCloseable { // warning here
}
abstract class InterruptedExceptionTest_C11 extends WithAbstractClose implements AutoCloseable {
}
// Interface use site tests
class UseSite_I1 {
void m(Supplier<InterruptedExceptionTest_I1> s) throws Exception {
try (InterruptedExceptionTest_I1 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_I2 {
void m(Supplier<InterruptedExceptionTest_I2> s) throws Exception {
try (InterruptedExceptionTest_I2 t = s.get()) {
t.hashCode();
}
}
}
class UseSite_I3 {
void m(Supplier<InterruptedExceptionTest_I3> s) throws Exception {
try (InterruptedExceptionTest_I3 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_I4 {
void m(Supplier<InterruptedExceptionTest_I4> s) throws Exception {
try (InterruptedExceptionTest_I4 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_I5 {
void m(Supplier<InterruptedExceptionTest_I5> s) throws Exception {
try (InterruptedExceptionTest_I5 t = s.get()) {
t.hashCode();
}
}
}
class UseSite_I6 {
void m(Supplier<InterruptedExceptionTest_I6> s) throws Exception {
try (InterruptedExceptionTest_I6 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_I7 {
void m(Supplier<InterruptedExceptionTest_I7> s) throws Exception {
try (InterruptedExceptionTest_I7 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_I8 {
void m(Supplier<InterruptedExceptionTest_I8> s) throws Exception {
try (InterruptedExceptionTest_I8 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_I9 {
void m(Supplier<InterruptedExceptionTest_I9> s) throws Exception {
try (InterruptedExceptionTest_I9 t = s.get()) {
t.hashCode();
}
}
}
// Abstract class use site tests
class UseSite_C1 {
void m(Supplier<InterruptedExceptionTest_C1> s) throws Exception {
try (InterruptedExceptionTest_C1 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_C2 {
void m(Supplier<InterruptedExceptionTest_C2> s) throws Exception {
try (InterruptedExceptionTest_C2 t = s.get()) {
t.hashCode();
}
}
}
class UseSite_C3 {
void m(Supplier<InterruptedExceptionTest_C3> s) throws Exception {
try (InterruptedExceptionTest_C3 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_C4 {
void m(Supplier<InterruptedExceptionTest_C4> s) throws Exception {
try (InterruptedExceptionTest_C4 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_C5 {
void m(Supplier<InterruptedExceptionTest_C5> s) throws Exception {
try (InterruptedExceptionTest_C5 t = s.get()) {
t.hashCode();
}
}
}
class UseSite_C6 {
void m(Supplier<InterruptedExceptionTest_C6> s) throws Exception {
try (InterruptedExceptionTest_C6 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_C7 {
void m(Supplier<InterruptedExceptionTest_C7> s) throws Exception {
try (InterruptedExceptionTest_C7 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_C8 {
void m(Supplier<InterruptedExceptionTest_C8> s) throws Exception {
try (InterruptedExceptionTest_C8 t = s.get()) { // warning here
t.hashCode();
}
}
}
class UseSite_C9 {
void m(Supplier<InterruptedExceptionTest_C9> s) throws Exception {
try (InterruptedExceptionTest_C9 t = s.get()) {
t.hashCode();
}
}
}
class UseSite_C10 {
void m(Supplier<InterruptedExceptionTest_C10> s) throws Exception {
try (InterruptedExceptionTest_C10 t = s.get()) { // warning here
t.hashCode();
}
}
}

View File

@ -0,0 +1,23 @@
InterruptedExceptionTest2.java:34:20: compiler.warn.try.resource.can.throw.interrupted.exc: InterruptedExceptionTest_I3
InterruptedExceptionTest2.java:38:20: compiler.warn.try.resource.can.throw.interrupted.exc: InterruptedExceptionTest_I4
InterruptedExceptionTest2.java:46:28: compiler.warn.try.resource.can.throw.interrupted.exc: InterruptedExceptionTest_I6
InterruptedExceptionTest2.java:50:28: compiler.warn.try.resource.can.throw.interrupted.exc: InterruptedExceptionTest_I7
InterruptedExceptionTest2.java:70:36: compiler.warn.try.resource.can.throw.interrupted.exc: InterruptedExceptionTest_C3
InterruptedExceptionTest2.java:74:36: compiler.warn.try.resource.can.throw.interrupted.exc: InterruptedExceptionTest_C4
InterruptedExceptionTest2.java:82:27: compiler.warn.try.resource.can.throw.interrupted.exc: InterruptedExceptionTest_C6
InterruptedExceptionTest2.java:86:27: compiler.warn.try.resource.can.throw.interrupted.exc: InterruptedExceptionTest_C7
InterruptedExceptionTest2.java:96:10: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_C10
InterruptedExceptionTest2.java:106:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_I1
InterruptedExceptionTest2.java:122:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_I3
InterruptedExceptionTest2.java:130:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_I4
InterruptedExceptionTest2.java:146:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_I6
InterruptedExceptionTest2.java:154:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_I7
InterruptedExceptionTest2.java:162:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_I8
InterruptedExceptionTest2.java:180:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_C1
InterruptedExceptionTest2.java:196:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_C3
InterruptedExceptionTest2.java:204:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_C4
InterruptedExceptionTest2.java:220:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_C6
InterruptedExceptionTest2.java:228:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_C7
InterruptedExceptionTest2.java:236:42: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_C8
InterruptedExceptionTest2.java:252:43: compiler.warn.try.resource.throws.interrupted.exc: InterruptedExceptionTest_C10
22 warnings

View File

@ -22,8 +22,15 @@
*/
// key: compiler.warn.try.resource.throws.interrupted.exc
// key: compiler.warn.try.resource.can.throw.interrupted.exc
// options: -Xlint:try
class TryResourceThrowsInterruptedException implements AutoCloseable {
public void close() throws InterruptedException {}
{
try (var t = new TryResourceThrowsInterruptedException()) {
t.hashCode();
} catch (InterruptedException e) {
}
}
}