[java] CloseResource: consider chained streams
This assumes that the underlaying stream is always the first argument in the constructor call.
This commit is contained in:
@ -18,6 +18,7 @@ import org.jaxen.JaxenException;
|
||||
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
|
||||
@ -160,6 +161,14 @@ public class CloseResourceRule extends AbstractJavaRule {
|
||||
if (!isMethodCall(expression) && runtimeType != null && runtimeType.getType() != null) {
|
||||
type = runtimeType;
|
||||
}
|
||||
|
||||
// consider cases, when the streams are chained
|
||||
// assumes, that the underlaying stream is always the first argument in the
|
||||
// constructor call.
|
||||
ASTExpression firstArgument = getAllocationFirstArgument(expression);
|
||||
if (firstArgument != null) {
|
||||
type = firstArgument;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAllowedResourceType(type)) {
|
||||
@ -176,11 +185,22 @@ public class CloseResourceRule extends AbstractJavaRule {
|
||||
}
|
||||
}
|
||||
|
||||
private ASTExpression getAllocationFirstArgument(ASTExpression expression) {
|
||||
List<ASTAllocationExpression> allocations = expression.findDescendantsOfType(ASTAllocationExpression.class);
|
||||
if (!allocations.isEmpty()) {
|
||||
ASTArgumentList argumentList = allocations.get(allocations.size() - 1).getFirstDescendantOfType(ASTArgumentList.class);
|
||||
if (argumentList != null) {
|
||||
return argumentList.getFirstChildOfType(ASTExpression.class);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isMethodCall(ASTExpression expression) {
|
||||
return expression != null
|
||||
&& expression.jjtGetNumChildren() > 0
|
||||
&& expression.jjtGetChild(0) instanceof ASTPrimaryExpression
|
||||
&& !expression.jjtGetChild(0).findChildrenOfType(ASTPrimarySuffix.class).isEmpty();
|
||||
&& expression.jjtGetChild(0).getFirstChildOfType(ASTPrimarySuffix.class) != null;
|
||||
}
|
||||
|
||||
private boolean isResourceTypeOrSubtype(TypeNode refType) {
|
||||
|
@ -1002,6 +1002,42 @@ public class CloseResourceTest {
|
||||
// TODO: close file
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>PrintWriter based on StringWriter</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
import java.io.*;
|
||||
|
||||
public class CloseResourcePrintWriter {
|
||||
public String run1() {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
|
||||
pw.println("Foo");
|
||||
String result = sw.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
public String run2() {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw, true);
|
||||
|
||||
pw.println("Foo");
|
||||
String result = sw.toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
public String run3() {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(new BufferedWriter(sw));
|
||||
|
||||
pw.println("Foo");
|
||||
return sw.toString();
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
Reference in New Issue
Block a user