[java]AvoidThrowingNullPointerException marks all NullPointerException objects as wrong, whether or not thrown (2580)
This commit is contained in:
@ -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);
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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>
|
||||
|
Reference in New Issue
Block a user