[java] New Rule: UseTryWithResources

Fixes #1405
This commit is contained in:
Andreas Dangel
2018-12-21 11:26:05 +01:00
parent dfd5b7b886
commit 8364d97e92
4 changed files with 218 additions and 0 deletions

View File

@ -14,6 +14,12 @@ This is a {{ site.pmd.release_type }} release.
### New and noteworthy
#### New Rules
* The new Java rule {% rule "java/bestpractices/UseTryWithResources" %) (`java-bestpractices`) searches
for try-blocks, that could be changed to a try-with-resources statement. This statement ensures that
each resource is closed at the end of the statement and is available since Java 7.
#### Modified Rules
* The Java rule {% rule "java/codestyle/LocalVariableCouldBeFinal" %} (`java-codestyle`) has a new
@ -24,6 +30,7 @@ This is a {{ site.pmd.release_type }} release.
* java-bestpractices
* [#658](https://github.com/pmd/pmd/issues/658): \[java] OneDeclarationPerLine: False positive for loops
* [#1405](https://github.com/pmd/pmd/issues/1405): \[java] New Rule: UseTryWithResources - Replace close and IOUtils.closeQuietly with try-with-resources
* java-codestyle
* [#1513](https://github.com/pmd/pmd/issues/1513): \[java] LocalVariableCouldBeFinal: allow excluding the variable in a for-each loop
* java-errorprone

View File

@ -1444,6 +1444,62 @@ public class Foo {
</example>
</rule>
<rule name="UseTryWithResources"
language="java"
minimumLanguageVersion="1.7"
since="6.11.0"
message="Consider use the try-with-resources statement instead of explicitly closing the resource"
class="net.sourceforge.pmd.lang.rule.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#usetrywithresources">
<description>
Java 7 introduced the try-with-resources statement. This statement ensures that each resource is closed at the end
of the statement. It avoids the need of explicitly closing the resources in a finally block. Additionally exceptions
are better handled: If an exception occurred both in the `try` block and `finally` block, then the exception from
the try block was suppressed. With the `try`-with-resources statement, the exception thrown from the try-block is
preserved.
</description>
<priority>3</priority>
<properties>
<property name="closeMethods" type="List[String]" delimiter="," description="Method names in finally block, which trigger this rule" value="close,closeQuietly"/>
<property name="version" value="2.0" />
<property name="xpath">
<value>
<![CDATA[
//TryStatement[not(ResourceSpecification)][FinallyStatement//Name[
tokenize(@Image, '\.')[last()] = $closeMethods
]]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class TryWithResources {
public void run() {
InputStream in = null;
try {
in = openInputStream();
int i = in.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) in.close();
} catch (IOException ignored) {
// ignored
}
}
// better use try-with-resources
try (InputStream in2 = openInputStream()) {
int i = in2.read();
}
}
}
]]>
</example>
</rule>
<rule name="UseVarargs"
language="java"
minimumLanguageVersion="1.5"

View File

@ -0,0 +1,11 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.bestpractices;
import net.sourceforge.pmd.testframework.PmdRuleTst;
public class UseTryWithResourcesTest extends PmdRuleTst {
// no additional unit tests
}

View File

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<test-data
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
<test-code>
<description>Code sample</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
public class TryWithResources {
public void run() {
InputStream in = null;
try {
in = openInputStream();
int i = in.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) in.close();
} catch (IOException ignored) {
// ignored
}
}
// better use try-with-resources
try (InputStream in2 = openInputStream()) {
int i = in2.read();
}
}
}
]]></code>
</test-code>
<test-code>
<description>With IOUtils.closeQuietly 1</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
public class TryWithResources {
public void run() {
InputStream in = null;
try {
in = openInputStream();
int i = in.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(in);
}
}
}
]]></code>
</test-code>
<test-code>
<description>With IOUtils.closeQuietly 2</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
public class TryWithResources {
public void run() {
InputStream in = null;
try {
in = openInputStream();
int i = in.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeQuietly(in);
}
}
}
]]></code>
</test-code>
<test-code>
<description>Multiple Resources</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>5</expected-linenumbers>
<code><![CDATA[
public class TryWithResources {
public void run() {
InputStream in1 = null;
InputStream in2 = null;
try {
in1 = openInputStream();
in2 = openInputStream();
int x = in1.read();
int y = in2.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in1 != null) in1.close();
} catch (IOException ignored) {
// ignored
}
IOUtils.closeQuietly(in2);
}
// better use try-with-resources
try (InputStream in3 = openInputStream(); InputStream in4 = openInputStream()) {
int x = in3.read();
int y = in4.read();
}
}
}
]]></code>
</test-code>
<test-code>
<description>Custom close methods</description>
<rule-property name="closeMethods">myClose2,myClose</rule-property>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
public class TryWithResources {
public void run() {
InputStream in = null;
try {
in = openInputStream();
int i = in.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
myClose(in);
}
// this block doesn't trigger the rule because of the custom close methods property
try {
in = openInputStream();
int i = in.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(in);
}
}
}
]]></code>
</test-code>
</test-data>