Skip to content

Commit

Permalink
AutoCloseableMustBeClosed doesn't match method overrides (#1685)
Browse files Browse the repository at this point in the history
AutoCloseableMustBeClosed doesn't match method overrides
  • Loading branch information
carterkozak authored Mar 9, 2021
1 parent 53c9967 commit f898554
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
import com.google.errorprone.matchers.Description;
import com.google.errorprone.matchers.Matcher;
import com.google.errorprone.matchers.Matchers;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.MethodTree;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import java.util.stream.BaseStream;

@AutoService(BugChecker.class)
Expand All @@ -48,7 +50,15 @@ public final class AutoCloseableMustBeClosed extends BugChecker implements Metho
Matchers.not(Matchers.methodIsConstructor()),
Matchers.methodReturns(Matchers.isSubtypeOf(AutoCloseable.class)),
// ignore Stream for now, see https://errorprone.info/bugpattern/StreamResourceLeak
Matchers.not(Matchers.methodReturns(Matchers.isSubtypeOf(BaseStream.class))));
Matchers.not(Matchers.methodReturns(Matchers.isSubtypeOf(BaseStream.class))),
// Avoid noise when methods override base interfaces that aren't annotated. In most cases
// the supertype reference is used, so annotations are less helpful on overrides.
// The override must be annotated MustBeClosed if the supertype is annotated.
Matchers.anyOf(
// It might be worthwhile to make an exception for generic types, for example
// Supplier<InputStream> subtypes should definitely be annotated.
Matchers.not(OverrideMethod.INSTANCE),
Matchers.hasAnnotationOnAnyOverriddenMethod(MUST_BE_CLOSED_TYPE)));

private static final Matcher<MethodTree> constructsAutoCloseable = Matchers.allOf(
Matchers.methodIsConstructor(),
Expand All @@ -63,9 +73,9 @@ public final class AutoCloseableMustBeClosed extends BugChecker implements Metho
Matchers.not(Matchers.hasAnnotation(CAN_IGNORE_RETURN_VALUE_TYPE));

private static final Matcher<MethodTree> methodShouldBeAnnotatedMustBeClosed = Matchers.allOf(
Matchers.anyOf(methodReturnsAutoCloseable, constructsAutoCloseable),
methodNotAnnotatedMustBeClosed,
methodNotAnnotatedIgnoreReturnValue);
methodNotAnnotatedIgnoreReturnValue,
Matchers.anyOf(methodReturnsAutoCloseable, constructsAutoCloseable));

@Override
public Description matchMethod(MethodTree tree, VisitorState state) {
Expand All @@ -78,4 +88,17 @@ public Description matchMethod(MethodTree tree, VisitorState state) {
}
return Description.NO_MATCH;
}

private enum OverrideMethod implements Matcher<MethodTree> {
INSTANCE;

@Override
public boolean matches(MethodTree tree, VisitorState state) {
MethodSymbol methodSym = ASTHelpers.getSymbol(tree);
if (methodSym == null) {
return false;
}
return !ASTHelpers.findSuperMethods(methodSym, state.getTypes()).isEmpty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,22 @@ public void testAlreadyAnnotated() {
.doTest();
}

@Test
public void testIgnoreOverride() {
compilationHelper
.addSourceLines(
"Test.java",
"import java.io.IOException;",
"import java.net.Socket;",
"import javax.net.ssl.SSLSocketFactory;",
"abstract class Test extends SSLSocketFactory {",
" public Socket createSocket() throws IOException {",
" return new Socket();",
" }",
"}")
.doTest();
}

@Test
public void testCanIgnoreReturnValue() {
compilationHelper
Expand Down Expand Up @@ -215,4 +231,43 @@ public void testSuggestedFixAddMustBeClosed() {
"}")
.doTest(BugCheckerRefactoringTestHelper.TestMode.TEXT_MATCH);
}

@Test
public void testFixOverridesAnnotatedMethod() {
refactoringTestHelper
.addInputLines(
"Test.java",
"import com.google.errorprone.annotations.MustBeClosed;",
"import java.io.*;",
"class Test {",
" interface Iface {",
" @MustBeClosed",
" InputStream stream() throws IOException;",
" }",
" static class Impl implements Iface {",
" @Override",
" public InputStream stream() throws IOException {",
" return new FileInputStream(new File(\"test\"));",
" }",
" }",
"}")
.addOutputLines(
"Test.java",
"import com.google.errorprone.annotations.MustBeClosed;",
"import java.io.*;",
"class Test {",
" interface Iface {",
" @MustBeClosed",
" InputStream stream() throws IOException;",
" }",
" static class Impl implements Iface {",
" @MustBeClosed",
" @Override",
" public InputStream stream() throws IOException {",
" return new FileInputStream(new File(\"test\"));",
" }",
" }",
"}")
.doTest();
}
}
5 changes: 5 additions & 0 deletions changelog/@unreleased/pr-1685.v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type: improvement
improvement:
description: AutoCloseableMustBeClosed doesn't match method overrides
links:
- https://github.com/palantir/gradle-baseline/pull/1685

0 comments on commit f898554

Please sign in to comment.