Merge pull request #3195 from oowekyala:update-UnnecessaryReturn

[java] Improve rule UnnecessaryReturn to detect more cases #3195
This commit is contained in:
Andreas Dangel committed 2021-04-10 19:03:38 +02:00
commit b75adc8169
7 files changed
+393 -36

No files matched your search

+1 -1
View File
@@ -110,7 +110,7 @@
<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/>
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/>
<rule ref="category/java/codestyle.xml/UnnecessaryModifier"/>
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryReturn"/> -->
<rule ref="category/java/codestyle.xml/UnnecessaryReturn"/>
<!-- <rule ref="category/java/codestyle.xml/UseDiamondOperator"/> -->
<rule ref="category/java/codestyle.xml/UseShortArrayInitializer"/>
<rule ref="category/java/codestyle.xml/UseUnderscoresInNumericLiterals"/>
+1
View File
@@ -151,6 +151,7 @@ The following previously deprecated rules have been finally removed:
* [#2299](https://github.com/pmd/pmd/issues/2299): \[java] UnnecessaryFullyQualifiedName false positive with similar package name
* [#2528](https://github.com/pmd/pmd/issues/2528): \[java] MethodNamingConventions - JUnit 5 method naming not support ParameterizedTest
* [#2739](https://github.com/pmd/pmd/issues/2739): \[java] UselessParentheses false positive for string concatenation
* [#3195](https://github.com/pmd/pmd/pull/3195): \[java] Improve rule UnnecessaryReturn to detect more cases
* java-errorprone
* [#1005](https://github.com/pmd/pmd/issues/1005): \[java] CloneMethodMustImplementCloneable triggers for interfaces
* [#2532](https://github.com/pmd/pmd/issues/2532): \[java] AvoidDecimalLiteralsInBigDecimalConstructor can not detect the case new BigDecimal(Expression)
@@ -1,34 +1,86 @@
/**
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.codestyle;
import net.sourceforge.pmd.lang.java.ast.ASTBlock;
import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
import net.sourceforge.pmd.lang.ast.NodeStream;
import net.sourceforge.pmd.lang.java.ast.ASTCompactConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
import net.sourceforge.pmd.lang.java.ast.ASTInitializer;
import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression;
import net.sourceforge.pmd.lang.java.ast.ASTLoopStatement;
import net.sourceforge.pmd.lang.java.ast.ASTMethodOrConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
import net.sourceforge.pmd.lang.java.ast.ASTStatement;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import net.sourceforge.pmd.lang.java.ast.ASTSwitchArrowBranch;
import net.sourceforge.pmd.lang.java.ast.ASTSwitchBranch;
import net.sourceforge.pmd.lang.java.ast.ASTSwitchExpression;
import net.sourceforge.pmd.lang.java.ast.ASTSwitchFallthroughBranch;
import net.sourceforge.pmd.lang.java.ast.ASTTryStatement;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
import net.sourceforge.pmd.lang.java.rule.internal.JavaRuleUtil;
public class UnnecessaryReturnRule extends AbstractJavaRule {
public class UnnecessaryReturnRule extends AbstractJavaRulechainRule {
@Override
public Object visit(ASTMethodDeclaration node, Object data) {
if (node.isVoid()) {
super.visit(node, data);
}
return data;
public UnnecessaryReturnRule() {
super(ASTReturnStatement.class);
}
@Override
public Object visit(ASTReturnStatement node, Object data) {
if (node.getParent() instanceof ASTStatement && node.getNthParent(2) instanceof ASTBlockStatement
&& node.getNthParent(3) instanceof ASTBlock && node.getNthParent(4) instanceof ASTMethodDeclaration) {
if (node.getNumChildren() > 0) {
return null;
}
NodeStream<ASTStatement> enclosingStatements =
node.ancestorsOrSelf()
.takeWhile(it -> !isCfgLimit(it))
.filterIs(ASTStatement.class);
if (enclosingStatements.all(UnnecessaryReturnRule::isLastStatementOfParent)) {
addViolation(data, node);
}
return data;
return null;
}
private boolean isCfgLimit(JavaNode it) {
return it instanceof ASTMethodOrConstructorDeclaration
|| it instanceof ASTCompactConstructorDeclaration
|| it instanceof ASTInitializer
|| it instanceof ASTLambdaExpression;
}
/**
* Returns true if this is the last statement of the parent node,
* ie the next statement to be executed is after the parent in the
* CFG.
*/
private static boolean isLastStatementOfParent(ASTStatement it) {
// Note that local class declaration statements could be ignored
// because they don't contribute anything to control flow. But this
// is rare enough that this has not been implemented. A corresponding
// test is in the test file.
JavaNode parent = it.getParent();
if (JavaRuleUtil.isLastChild(it)) {
if (parent instanceof ASTSwitchArrowBranch) {
return !isBranchOfSwitchExpr((ASTSwitchBranch) parent);
} else if (parent instanceof ASTSwitchFallthroughBranch) {
return JavaRuleUtil.isLastChild(parent) && !isBranchOfSwitchExpr((ASTSwitchBranch) parent);
} else {
return !(parent instanceof ASTLoopStatement); // returns break the loop so are not unnecessary (though it could be replaced by break)
}
}
// so we're not the last child...
return parent instanceof ASTIfStatement // maybe we're before the else clause
|| parent instanceof ASTTryStatement; // maybe we're the body of a try
// also maybe we're the body of a do/while, but that is a loop, so it's necessary
}
private static boolean isBranchOfSwitchExpr(ASTSwitchBranch branch) {
return branch.getParent() instanceof ASTSwitchExpression;
}
}
@@ -23,6 +23,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.lang.ast.GenericToken;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.NodeStream;
import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken;
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
@@ -737,4 +738,12 @@ public final class JavaRuleUtil {
private static boolean isStringConcatExpression(ASTExpression e) {
return BinaryOp.isInfixExprWithOperator(e, BinaryOp.ADD) && TypeTestUtil.isA(String.class, e);
}
/**
* Returns true if the node is the last child of its parent (or is the root node).
*/
public static boolean isLastChild(Node it) {
Node parent = it.getParent();
return parent == null || it.getIndexInParent() == parent.getNumChildren() - 1;
}
}
@@ -1624,11 +1624,12 @@ public class Bar {
<rule name="UnnecessaryReturn"
language="java"
since="1.3"
message="Avoid unnecessary return statements"
message="Unnecessary return statement"
class="net.sourceforge.pmd.lang.java.rule.codestyle.UnnecessaryReturnRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#unnecessaryreturn">
<description>
Avoid the use of unnecessary return statements.
Avoid the use of unnecessary return statements. A return is unnecessary when no
instructions follow anyway.
</description>
<priority>3</priority>
<example>
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.codestyle;
import net.sourceforge.pmd.testframework.PmdRuleTst;
@org.junit.Ignore("Rule has not been updated yet")
public class UnnecessaryReturnTest extends PmdRuleTst {
// no additional unit tests
}