[java]AvoidThrowingNullPointerException marks all NullPointerException objects as wrong, whether or not thrown (2580)

This commit is contained in:
Mykhailo Palahuta
2020-07-14 11:00:44 +03:00
parent c93414d7b5
commit 061c9656cc
4 changed files with 105 additions and 12 deletions

View File

@ -0,0 +1,77 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.design;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
/**
* Finds <code>throw</code> statements containing <code>NullPointerException</code>
* instances as thrown values
*
* @author <a href="mailto:michaeller.2012@gmail.com">Mykhailo Palahuta</a>
*/
public class AvoidThrowingNullPointerExceptionRule extends AbstractJavaRule {
@Override
public Object visit(ASTClassOrInterfaceBody node, Object data) {
if (bodyHasThrowNullPointerExceptionStatement(node)) {
addViolation(data, node);
}
return super.visit(node, data);
}
private boolean bodyHasThrowNullPointerExceptionStatement(ASTClassOrInterfaceBody body) {
List<ASTThrowStatement> throwStatements = body.findDescendantsOfType(ASTThrowStatement.class);
List<String> npeInstances = getNullPointerExceptionInstances(body);
for (ASTThrowStatement throwStatement : throwStatements) {
if (throwsNullPointerException(throwStatement, npeInstances)) {
return true;
}
}
return false;
}
private List<String> getNullPointerExceptionInstances(ASTClassOrInterfaceBody body) {
List<ASTAllocationExpression> allocations = body.findDescendantsOfType(ASTAllocationExpression.class);
List<String> npeInstances = new ArrayList<>();
for (ASTAllocationExpression allocation : allocations) {
if (allocatesNullPointerException(allocation)) {
String assignedVarName = getNameOfAssignedVariable(allocation);
npeInstances.add(assignedVarName);
}
}
return npeInstances;
}
private boolean allocatesNullPointerException(ASTAllocationExpression allocation) {
Class<?> allocatedType = getAllocatedInstanceType(allocation);
return allocatedType != null && NullPointerException.class.isAssignableFrom(allocatedType);
}
private Class<?> getAllocatedInstanceType(ASTAllocationExpression allocation) {
List<ASTClassOrInterfaceType> allocatedTypes = allocation
.findDescendantsOfType(ASTClassOrInterfaceType.class);
return allocatedTypes.isEmpty() ? null : allocatedTypes.get(0).getType();
}
private String getNameOfAssignedVariable(ASTAllocationExpression allocation) {
List<ASTVariableDeclarator> variableDeclarators = allocation.getParent()
.findDescendantsOfType(ASTVariableDeclarator.class);
return variableDeclarators.isEmpty() ? null : variableDeclarators.get(0).getName();
}
private boolean throwsNullPointerException(ASTThrowStatement throwStatement, List<String> npeInstances) {
String thrownImage = throwStatement.getFirstClassOrInterfaceTypeImage();
return "NullPointerException".equals(thrownImage) || npeInstances.contains(thrownImage);
}
}

View File

@ -200,7 +200,7 @@ public void bar() {
language="java"
since="1.8"
message="Avoid throwing null pointer exceptions."
class="net.sourceforge.pmd.lang.rule.XPathRule"
class="net.sourceforge.pmd.lang.java.rule.design.AvoidThrowingNullPointerExceptionRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_design.html#avoidthrowingnullpointerexception">
<description>
<![CDATA[
@ -234,16 +234,6 @@ public class Foo {
]]>
</description>
<priority>1</priority>
<properties>
<property name="version" value="2.0"/>
<property name="xpath">
<value>
<![CDATA[
//AllocationExpression/ClassOrInterfaceType[@Image='NullPointerException']
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class Foo {

View File

@ -12,6 +12,32 @@ public class Foo {
void bar() {
throw new NullPointerException();
}
}
]]></code>
</test-code>
<test-code>
<description>no problems if NullPointerException is only instantiated but not thrown</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
void bar() {
Exception e = new NullPointerException("Test message");
String msg = e.getMessage();
}
}
]]></code>
</test-code>
<test-code>
<description>problem should be detected even if NullPointerException is stored in some intermediate variable</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
void bar() {
Exception e = new NullPointerException();
throw e;
}
}
]]></code>
</test-code>