[java] Reimplement UseTryWithResources as Java rule

This commit is contained in:
Andreas Dangel
2021-07-08 12:26:50 +02:00
parent 5b31a74735
commit 6266b1ce03
2 changed files with 76 additions and 18 deletions

View File

@ -0,0 +1,75 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.bestpractices;
import static net.sourceforge.pmd.properties.PropertyFactory.stringListProperty;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTFinallyStatement;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTTryStatement;
import net.sourceforge.pmd.lang.java.ast.TypeNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
import net.sourceforge.pmd.properties.PropertyDescriptor;
public final class UseTryWithResourcesRule extends AbstractJavaRule {
private static final PropertyDescriptor<List<String>> CLOSE_METHODS =
stringListProperty("closeMethods")
.desc("Method names in finally block, which trigger this rule")
.defaultValues("close", "closeQuietly")
.delim(',')
.build();
public UseTryWithResourcesRule() {
addRuleChainVisit(ASTTryStatement.class);
definePropertyDescriptor(CLOSE_METHODS);
}
@Override
public Object visit(ASTTryStatement node, Object data) {
ASTFinallyStatement finallyClause = node.getFinallyClause();
if (finallyClause != null) {
List<ASTName> methods = findCloseMethods(finallyClause.findDescendantsOfType(ASTName.class));
for (ASTName method : methods) {
TypeNode typeNode = getType(method);
if (TypeTestUtil.isA(AutoCloseable.class, typeNode)) {
addViolation(data, node);
break; // only report the first closeable
}
}
}
return data;
}
private TypeNode getType(ASTName method) {
ASTArguments arguments = method.getNthParent(2).getFirstDescendantOfType(ASTArguments.class);
if (arguments.size() > 0) {
return (ASTExpression) arguments.getChild(0).getChild(0);
}
return method;
}
private List<ASTName> findCloseMethods(List<ASTName> names) {
List<ASTName> potentialCloses = new ArrayList<>();
for (ASTName name : names) {
String image = name.getImage();
int lastDot = image.lastIndexOf('.');
if (lastDot > -1) {
image = image.substring(lastDot + 1);
}
if (getProperty(CLOSE_METHODS).contains(image)) {
potentialCloses.add(name);
}
}
return potentialCloses;
}
}

View File

@ -1970,7 +1970,7 @@ public class UseStandardCharsets {
since="6.12.0"
typeResolution="true"
message="Consider using a try-with-resources statement instead of explicitly closing the resource"
class="net.sourceforge.pmd.lang.rule.XPathRule"
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UseTryWithResourcesRule"
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
@ -1980,23 +1980,6 @@ the try block was suppressed. With the `try`-with-resources statement, the excep
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[FinallyStatement//Name[
tokenize(@Image, '\.')[last()] = $closeMethods
][
pmd-java:typeIs('java.lang.AutoCloseable')
or
../../PrimarySuffix/Arguments//PrimaryPrefix[pmd-java:typeIs('java.lang.AutoCloseable')]
]]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class TryWithResources {