diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 772bb038de76..f93fa8609048 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1757,6 +1757,7 @@ logger.class.name=Logger class name ignore.exceptions.declared.on.library.override.option=Ignore exceptions declared on methods overriding a &library method allow.resource.to.be.opened.inside.a.try.block=Allow resource to be opened inside a 'try' block any.method.may.close.resource.argument=Any method may close resource argument +show.warning.for.stream.holding.resource=Show warning for java.util.Stream holding resource log.method.name=Logging method name log.condition.text=Log condition text ignore.if.annotated.by=Ignore if annotated by diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/resources/AutoCloseableResourceInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/resources/AutoCloseableResourceInspectionBase.java index 353bcb4a0b68..9546525742dc 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/resources/AutoCloseableResourceInspectionBase.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/resources/AutoCloseableResourceInspectionBase.java @@ -42,6 +42,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static com.intellij.util.ObjectUtils.tryCast; + /** * @author Bas Leijdekkers */ @@ -54,6 +56,8 @@ public class AutoCloseableResourceInspectionBase extends ResourceInspection { @SuppressWarnings("PublicField") public boolean ignoreFromMethodCall = false; + public boolean showWarningForStreamHoldingResource = true; + final List ignoredTypes = new ArrayList<>(DEFAULT_IGNORED_TYPES); protected final MethodMatcher myMethodMatcher; @@ -67,6 +71,8 @@ public class AutoCloseableResourceInspectionBase extends ResourceInspection { .finishDefault(); } + CallMatcher STREAM_HOLDING_RESOURCE = CallMatcher.staticCall("java.nio.file.Files", "lines", "walk", "list", "find"); + @Nls @NotNull @Override @@ -148,7 +154,12 @@ public class AutoCloseableResourceInspectionBase extends ResourceInspection { @Override protected boolean isResourceCreation(PsiExpression expression) { return TypeUtils.expressionHasTypeOrSubtype(expression, CommonClassNames.JAVA_LANG_AUTO_CLOSEABLE) && - !TypeUtils.expressionHasTypeOrSubtype(expression, ignoredTypes); + (isStreamHoldingResource(expression) + || !TypeUtils.expressionHasTypeOrSubtype(expression, ignoredTypes)); + } + + private boolean isStreamHoldingResource(PsiExpression expression) { + return showWarningForStreamHoldingResource && STREAM_HOLDING_RESOURCE.matches(tryCast(expression, PsiMethodCallExpression.class)); } @Override @@ -178,7 +189,7 @@ public class AutoCloseableResourceInspectionBase extends ResourceInspection { if (ignoreFromMethodCall || myMethodMatcher.matches(expression) || isSafelyClosedResource(expression)) { return; } - registerMethodCallError(expression, expression.getType(), Boolean.TRUE); + registerMethodCallError(expression, expression.getType(), !isStreamHoldingResource(expression)); } @Override diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java index 64117ddfe710..3206904b097d 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/resources/AutoCloseableResourceInspection.java @@ -64,6 +64,7 @@ public class AutoCloseableResourceInspection extends AutoCloseableResourceInspec checkBox.addChangeListener(e -> table2.setEnabled(!ignoreFromMethodCall)); panel.add(checkBox); panel.add(new CheckBox(InspectionGadgetsBundle.message("any.method.may.close.resource.argument"), this, "anyMethodMayClose")); + panel.add(new CheckBox(InspectionGadgetsBundle.message("show.warning.for.stream.holding.resource"), this, "showWarningForStreamHoldingResource")); return panel; } } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/resources/AutoCloseableResourceInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/resources/AutoCloseableResourceInspectionTest.java index 618e10092a98..80268433860c 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/resources/AutoCloseableResourceInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/resources/AutoCloseableResourceInspectionTest.java @@ -16,7 +16,9 @@ package com.siyeh.ig.resources; import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.testFramework.LightProjectDescriptor; import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.NotNull; /** * @author Bas Leijdekkers @@ -74,6 +76,7 @@ public class AutoCloseableResourceInspectionTest extends LightInspectionTestCase } public void testARM() { + mockSql(); doTest("import java.sql.*;\n" + "class X {\n" + " void m(Driver driver) throws SQLException {\n" + @@ -81,12 +84,29 @@ public class AutoCloseableResourceInspectionTest extends LightInspectionTestCase " PreparedStatement statement = connection.prepareStatement(\"SELECT *\");\n" + " ResultSet resultSet = statement.executeQuery()) {\n" + " while (resultSet.next()) { resultSet.getMetaData(); }\n" + - " }\n" + + " } catch(Exception e) {}\n" + " }\n" + "}"); } + private void mockSql() { + addEnvironmentClass("package java.sql;\n" + + "public interface Driver { Connection connect(String s, Object o) throws SQLException;}"); + addEnvironmentClass("package java.sql;\n" + + "public interface Connection extends AutoCloseable { PreparedStatement prepareStatement(String s);}"); + addEnvironmentClass("package java.sql;\n" + + "public interface PreparedStatement extends AutoCloseable { ResultSet executeQuery();}"); + addEnvironmentClass("package java.sql;\n" + + "public class SQLException extends Exception {}"); + addEnvironmentClass("package java.sql;\n" + + "public interface ResultSet extends AutoCloseable {\n" + + " boolean next();\n" + + " void getMetaData();\n" + + "}"); + } + public void testSimple() { + mockSql(); doTest("import java.sql.*;" + "class X {" + " void m(Driver driver) throws SQLException {" + @@ -163,6 +183,28 @@ public class AutoCloseableResourceInspectionTest extends LightInspectionTestCase "}"); } + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JAVA_8; + } + + public void testFilesMethod() { + addEnvironmentClass("package java.nio.file;\n" + + "import java.util.stream.Stream;\n" + + "public final class Files {\n" + + " public static Stream lines(Path path) {return Stream.empty();}\n" + + "}"); + doTest("import java.io.*;\n" + + "import java.nio.file.Files;\n" + + "import java.util.stream.Stream;\n" + + "class X {\n" + + " private static void example(int a) {\n" + + " Stream s = Files.' used without 'try'-with-resources statement\">lines(null);\n" + + " }\n" + + "}"); + } + public void testClosedResource() { doTest("import java.io.*;\n" + "\n" +