Finish loops
This commit is contained in:
@ -5,9 +5,7 @@
|
||||
package net.sourceforge.pmd.lang.java.rule.errorprone;
|
||||
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@ -16,7 +14,11 @@ import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAssignmentOperator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBreakStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTDoStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForInit;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTForUpdate;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
@ -24,6 +26,7 @@ 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.ASTReturnStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
|
||||
@ -79,13 +82,8 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
|
||||
static class LivenessVisitor extends JavaParserVisitorAdapter {
|
||||
|
||||
|
||||
private final Deque<ScopeData> breakAddresses = new ArrayDeque<>();
|
||||
private final Map<String, ScopeData> namedBreaks = new HashMap<>();
|
||||
|
||||
// following deals with control flow
|
||||
|
||||
|
||||
@Override
|
||||
public Object visit(JavaNode node, Object data) {
|
||||
|
||||
@ -99,29 +97,73 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
|
||||
@Override
|
||||
public Object visit(ASTIfStatement node, Object data) {
|
||||
ScopeData before = (ScopeData) node.getCondition().jjtAccept(this, data);
|
||||
ScopeData before = acceptOpt(node.getCondition(), (ScopeData) data);
|
||||
|
||||
ScopeData thenData = before.fork();
|
||||
thenData = (ScopeData) node.getThenBranch().jjtAccept(this, thenData);
|
||||
if (node.hasElse()) {
|
||||
ScopeData elseData = (ScopeData) node.getElseBranch().jjtAccept(this, before.fork());
|
||||
return thenData.join(elseData);
|
||||
} else {
|
||||
return before.join(thenData);
|
||||
}
|
||||
ScopeData thenData = acceptOpt(node.getThenBranch(), before.fork());
|
||||
ScopeData elseData = acceptOpt(node.getElseBranch(), before.fork());
|
||||
|
||||
return thenData.join(elseData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTWhileStatement node, Object data) {
|
||||
ScopeData before = (ScopeData) node.getCondition().jjtAccept(this, data);
|
||||
// perform a few "iterations", to make sure that assignments in
|
||||
// the body can affect themselves in the next iteration, and
|
||||
// that they affect the condition
|
||||
ScopeData before = acceptOpt(node.getCondition(), (ScopeData) data);
|
||||
|
||||
ScopeData iter = (ScopeData) node.getBody().jjtAccept(this, before.fork());
|
||||
iter = (ScopeData) node.getCondition().jjtAccept(this, iter);
|
||||
iter = (ScopeData) node.getBody().jjtAccept(this, iter);
|
||||
ScopeData iter = acceptOpt(node.getBody(), before.fork());
|
||||
iter = acceptOpt(node.getCondition(), iter);
|
||||
iter = acceptOpt(node.getBody(), iter);
|
||||
|
||||
return before.join(iter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDoStatement node, Object data) {
|
||||
// same as while but don't check the condition first
|
||||
ScopeData before = (ScopeData) data;
|
||||
|
||||
ScopeData iter = acceptOpt(node.getBody(), before.fork());
|
||||
iter = acceptOpt(node.getCondition(), iter);
|
||||
iter = acceptOpt(node.getBody(), iter);
|
||||
|
||||
return before.join(iter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTForStatement node, Object data) {
|
||||
ASTStatement body = node.getBody();
|
||||
if (node.isForeach()) {
|
||||
// the iterable expression
|
||||
ScopeData before = (ScopeData) node.getChild(1).jjtAccept(this, data);
|
||||
|
||||
ScopeData iter = acceptOpt(body, before.fork());
|
||||
iter = acceptOpt(body, iter); // the body must be able to affect itself
|
||||
|
||||
return before.join(iter);
|
||||
} else {
|
||||
ASTForInit init = node.getFirstChildOfType(ASTForInit.class);
|
||||
ASTExpression cond = node.getCondition();
|
||||
ASTForUpdate update = node.getFirstChildOfType(ASTForUpdate.class);
|
||||
|
||||
ScopeData before = (ScopeData) data;
|
||||
before = acceptOpt(init, before);
|
||||
before = acceptOpt(cond, before);
|
||||
|
||||
ScopeData iter = acceptOpt(body, before.fork());
|
||||
iter = acceptOpt(update, iter);
|
||||
iter = acceptOpt(cond, iter);
|
||||
iter = acceptOpt(body, iter); // the body must be able to affect itself
|
||||
|
||||
return before.join(iter);
|
||||
}
|
||||
}
|
||||
|
||||
private ScopeData acceptOpt(JavaNode node, ScopeData before) {
|
||||
return node == null ? before : (ScopeData) node.jjtAccept(this, before);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTThrowStatement node, Object data) {
|
||||
data = super.visit(node, data);
|
||||
@ -216,14 +258,14 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
if (suffix.isArguments() || suffix.isArrayDereference()) {
|
||||
return null;
|
||||
}
|
||||
return findVar(primary.getScope(), true, suffix.getImage());
|
||||
return findVar(primary.getScope(), true, substringBeforeFirst(suffix.getImage(), '.'));
|
||||
} else {
|
||||
if (inLhs && primary.getNumChildren() > 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (prefix.getChild(0) instanceof ASTName) {
|
||||
return findVar(prefix.getScope(), false, prefix.getChild(0).getImage());
|
||||
return findVar(prefix.getScope(), false, substringBeforeFirst(prefix.getChild(0).getImage(), '.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,6 +273,11 @@ public class UnusedAssignmentRule extends AbstractJavaRule {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String substringBeforeFirst(String str, char delim) {
|
||||
int i = str.indexOf(delim);
|
||||
return i < 0 ? str : str.substring(0, i);
|
||||
}
|
||||
|
||||
private VariableNameDeclaration findVar(Scope scope, boolean isThis, String name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
|
@ -179,8 +179,12 @@ public class Foo {
|
||||
|
||||
<test-code>
|
||||
<description>#1393 PMD hanging during DataflowAnomalyAnalysis</description>
|
||||
<!-- Note: due to https://sourceforge.net/p/pmd/bugs/1383/ the 3 problems are false positives! -->
|
||||
<expected-problems>3</expected-problems>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>10,19</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>The value assigned to variable 'fail' is never used</message>
|
||||
<message>The value assigned to variable 'fail' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
public class LoopTest {
|
||||
public static void main(String[] args) {
|
||||
@ -255,18 +259,65 @@ class Test{
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 2. DU-Anomaly(a)</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>5</expected-linenumbers>
|
||||
<description>For loop</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
int a = 0 ;
|
||||
for(int i = 0 ; i <= 10; i ++){
|
||||
a = a+3;
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>For loop 2</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>3,5</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>The value assigned to variable 'a' is never used</message>
|
||||
<message>The value assigned to variable 'a' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
int a = 0 ;
|
||||
for(int i = 0 ; i <= 10; i ++){
|
||||
a = a+3;
|
||||
a = i * 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>For loop 3</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
int a = 0 ;
|
||||
for(int i = 0 ; i <= 10; i ++){
|
||||
a = i * 3;
|
||||
}
|
||||
System.out.println(a);
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>For loop 4</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
int a = 0 ;
|
||||
for(int i = 0 ; (i + a) <= 10; i ++){
|
||||
a = i * 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -409,12 +460,8 @@ class Test{
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 5. DU-Anomaly(a)</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>6</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>Found 'DU'-anomaly for variable 'a' (lines '6'-'9').</message>
|
||||
</expected-messages>
|
||||
<description>Do while 0</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
@ -429,6 +476,55 @@ class Test{
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Do while 1</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>3</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>The value assigned to variable 'a' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
int a = 0;
|
||||
int i = 0;
|
||||
do {
|
||||
a = i+3;
|
||||
i += 3;
|
||||
} while ((a+i) < 30);
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Do while with break</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>7,8</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>The value assigned to variable 'i' is never used</message>
|
||||
<message>The value assigned to variable 'a' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
int a = 0;
|
||||
int i = 0;
|
||||
do {
|
||||
if (a >= 20) {
|
||||
i = 4;
|
||||
a *= 5;
|
||||
break;
|
||||
}
|
||||
|
||||
a = i + 3;
|
||||
i += 3;
|
||||
} while (i < 30);
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 6. DU-Anomaly(a)</description>
|
||||
<expected-problems>4</expected-problems>
|
||||
@ -482,11 +578,11 @@ class Test{
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 9. DU-Anomaly(t1)</description>
|
||||
<description>Usage as LHS of method</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>5</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>Found 'DU'-anomaly for variable 't1' (lines '5'-'6').</message>
|
||||
<message>The value assigned to variable 't1' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
@ -500,11 +596,11 @@ class Test{
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 12. DU-Anomaly(t1)</description>
|
||||
<description>Assignment in operand</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>6</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>Found 'DU'-anomaly for variable 't1' (lines '6'-'7').</message>
|
||||
<message>The value assigned to variable 't1' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
@ -519,7 +615,27 @@ class Test{
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 13</description>
|
||||
<description>Assignment in operand 2</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>7</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>The value assigned to variable 't1' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
public static void main(String[] args){
|
||||
int t1 = 0 ;
|
||||
int t2 = 0 ;
|
||||
// the left assignment reaches the right of the ==
|
||||
if ( (t1 = t1 + t2)
|
||||
== (t1 = t2 * t1) ); // only this assignment is unused
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Assignment in operand 3</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
@ -534,12 +650,12 @@ class Test{
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#1905 [java] DataflowAnomalyAnalysis Rule in right order : Case 14. DU-Anomaly(t1, t2)</description>
|
||||
<description>Assignment in operand 4</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>4,6</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>Found 'DU'-anomaly for variable 't2' (lines '4'-'7').</message>
|
||||
<message>Found 'DU'-anomaly for variable 't1' (lines '6'-'7').</message>
|
||||
<message>The value assigned to variable 't2' is never used</message>
|
||||
<message>The value assigned to variable 't1' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
class Test{
|
||||
@ -558,13 +674,50 @@ class Test{
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>4</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>Found 'DU'-anomaly for variable 'a' (lines '4'-'5').</message>
|
||||
<message>The value assigned to variable 'a' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
public class Test {
|
||||
public void test(){
|
||||
int a = 0;
|
||||
a = a + 3;
|
||||
|
||||
int i = 0;
|
||||
i += 3; // same with compound
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>Compound assignment</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>4</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>The value assigned to variable 'a' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
public class Test {
|
||||
public void test(){
|
||||
int a = 0;
|
||||
a += 3; // same with compound
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
<test-code>
|
||||
<description>Another case</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>3,5</expected-linenumbers>
|
||||
<expected-messages>
|
||||
<message>The value assigned to variable 'iter' is never used</message>
|
||||
<message>The value assigned to variable 'iter' is never used</message>
|
||||
</expected-messages>
|
||||
<code><![CDATA[
|
||||
public class Test {
|
||||
public void test(){
|
||||
ScopeData iter = acceptOpt(node.getBody(), before.fork()); // this assignment is unused
|
||||
iter = acceptOpt(node.getCondition(), before.fork());
|
||||
iter = acceptOpt(node.getBody(), iter);
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
|
Reference in New Issue
Block a user