Improve finally
This commit is contained in:
1 parent
972610fe89
commit
e228e5590f
3 files changed
+91
-29
No files matched your search
@@ -49,7 +49,7 @@ public class ASTTryStatement extends AbstractJavaNode {
|
||||
* Returns the body of this try statement.
|
||||
*/
|
||||
public ASTBlock getBody() {
|
||||
return (ASTBlock) getChild(1);
|
||||
return (ASTBlock) getFirstChildOfType(ASTBlock.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+54
-23
@@ -39,7 +39,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTPreDecrementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPreIncrementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTResourceSpecification;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatement;
|
||||
@@ -74,6 +73,9 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
|
||||
@Override
|
||||
public Object visit(ASTMethodDeclaration node, Object data) {
|
||||
if (node.isAbstract()) {
|
||||
return data;
|
||||
}
|
||||
|
||||
AlgoState endState = (AlgoState) node.getBody().jjtAccept(new ReachingDefsVisitor(), new AlgoState());
|
||||
|
||||
@@ -220,6 +222,26 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
final AlgoState before = (AlgoState) data;
|
||||
ASTFinallyStatement finallyClause = node.getFinallyClause();
|
||||
|
||||
/*
|
||||
<before>
|
||||
try (<resources>) {
|
||||
<body>
|
||||
} catch (IOException e) {
|
||||
<catch>
|
||||
} finally {
|
||||
<finally>
|
||||
}
|
||||
<end>
|
||||
|
||||
There is a path <before> -> <resources> -> <body> -> <finally> -> <end>
|
||||
and for each catch, <before> -> <catch> -> <finally> -> <end>
|
||||
|
||||
Except that abrupt completion before the <finally> jumps
|
||||
to the <finally> and completes abruptly for the same
|
||||
reason (if the <finally> completes normally), which
|
||||
means it doesn't go to <end>
|
||||
*/
|
||||
|
||||
if (finallyClause != null) {
|
||||
before.myFinally = before.forkEmpty();
|
||||
}
|
||||
@@ -236,12 +258,17 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
}
|
||||
|
||||
AlgoState finalState;
|
||||
finalState = bodyState.join(exceptionalState);
|
||||
if (finallyClause != null) {
|
||||
finalState = before.myFinally.join(bodyState).join(exceptionalState);
|
||||
finalState = acceptOpt(finallyClause, finalState);
|
||||
// this represents the finally clause when it was entered
|
||||
// because of abrupt completion
|
||||
// since we don't know when it terminated we must join it with before
|
||||
AlgoState abruptFinally = before.myFinally.join(before);
|
||||
acceptOpt(finallyClause, abruptFinally);
|
||||
before.myFinally = null;
|
||||
} else {
|
||||
finalState = bodyState.join(exceptionalState);
|
||||
|
||||
// this is the normal finally
|
||||
finalState = acceptOpt(finallyClause, finalState);
|
||||
}
|
||||
return finalState;
|
||||
}
|
||||
@@ -478,22 +505,23 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
if (primary instanceof ASTPrimaryExpression) {
|
||||
ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) primary.getChild(0);
|
||||
|
||||
if (prefix.usesThisModifier()) {
|
||||
if (primary.getNumChildren() != 2 && inLhs) {
|
||||
return null;
|
||||
}
|
||||
ASTPrimarySuffix suffix = (ASTPrimarySuffix) primary.getChild(1);
|
||||
if (suffix.isArguments() || suffix.isArrayDereference()) {
|
||||
return null;
|
||||
}
|
||||
return findVar(primary.getScope(), true, firstIdent(suffix.getImage()));
|
||||
} else {
|
||||
// if (prefix.usesThisModifier()) {
|
||||
// if (primary.getNumChildren() < 2) {
|
||||
// return null;
|
||||
// }
|
||||
// ASTPrimarySuffix suffix = (ASTPrimarySuffix) primary.getChild(1);
|
||||
// if (suffix.isArguments() || suffix.isArrayDereference() || suffix.getImage() == null) {
|
||||
// return null;
|
||||
// }
|
||||
// return findVar(primary.getScope(), true, firstIdent(suffix.getImage()));
|
||||
// } else
|
||||
{
|
||||
if (inLhs && primary.getNumChildren() > 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prefix.getChild(0) instanceof ASTName) {
|
||||
return findVar(prefix.getScope(), false, firstIdent(prefix.getChild(0).getImage()));
|
||||
if (prefix.getNumChildren() > 0 && (prefix.getChild(0) instanceof ASTName)) {
|
||||
return findVar(prefix.getScope(), identOf(inLhs, prefix.getChild(0).getImage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -501,22 +529,25 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String firstIdent(String str) {
|
||||
private static String identOf(boolean inLhs, String str) {
|
||||
int i = str.indexOf('.');
|
||||
return i < 0 ? str : str.substring(0, i);
|
||||
return i < 0 ? str
|
||||
: inLhs ? null
|
||||
: str.substring(0, i);
|
||||
}
|
||||
|
||||
private VariableNameDeclaration findVar(Scope scope, boolean isThis, String name) {
|
||||
private VariableNameDeclaration findVar(Scope scope, String name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
if (isThis) {
|
||||
scope = scope.getEnclosingScope(ClassScope.class);
|
||||
}
|
||||
|
||||
while (scope != null) {
|
||||
for (VariableNameDeclaration decl : scope.getDeclarations(VariableNameDeclaration.class).keySet()) {
|
||||
if (decl.getImage().equals(name)) {
|
||||
if (scope instanceof ClassScope) {
|
||||
// don't handle fields
|
||||
return null;
|
||||
}
|
||||
return decl;
|
||||
}
|
||||
}
|
||||
|
||||
+36
-5
@@ -1099,11 +1099,7 @@ public class Foo {
|
||||
|
||||
<test-code>
|
||||
<description>Try/catch finally</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>4</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>The value assigned to variable 'a' is never used (overwritten on lines 6 and 8)</message>
|
||||
</expected-messages>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
|
||||
@@ -1170,6 +1166,41 @@ class Foo {
|
||||
return a;
|
||||
}
|
||||
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>Abstract method NPE</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
|
||||
abstract class Foo {
|
||||
|
||||
public abstract int foo();
|
||||
|
||||
interface Bar {
|
||||
int bar();
|
||||
}
|
||||
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>FP in finally</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
|
||||
class Foo {
|
||||
public Object intercept(Object proxy) throws Throwable {
|
||||
Object oldProxy = null; // FP here
|
||||
try {
|
||||
oldProxy = new Object[] { proxy };
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
System.out.println(oldProxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
Reference in new issue
Block a user