[java] RedundantFieldInitializer can not detect a special case for char initialize: char foo = '\0';
This commit is contained in:
1 parent
25405eb870
commit
a707d94513
2 files changed
+88
-108
No files matched your search
+77
-108
@@ -4,17 +4,15 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.rule.performance;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTCastExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||
|
||||
/**
|
||||
@@ -32,115 +30,86 @@ public class RedundantFieldInitializerRule extends AbstractJavaRule {
|
||||
|
||||
@Override
|
||||
public Object visit(ASTFieldDeclaration fieldDeclaration, Object data) {
|
||||
// Finals can only be initialized once.
|
||||
if (fieldDeclaration.isFinal()) {
|
||||
return data;
|
||||
}
|
||||
|
||||
// Look for a match to the following XPath:
|
||||
// VariableDeclarator/VariableInitializer/Expression/PrimaryExpression/PrimaryPrefix/Literal
|
||||
for (ASTVariableDeclarator variableDeclarator : fieldDeclaration
|
||||
.findChildrenOfType(ASTVariableDeclarator.class)) {
|
||||
if (variableDeclarator.getNumChildren() > 1) {
|
||||
final Node variableInitializer = variableDeclarator.getChild(1);
|
||||
if (variableInitializer.getChild(0) instanceof ASTExpression) {
|
||||
final Node expression = variableInitializer.getChild(0);
|
||||
final Node primaryExpression;
|
||||
if (expression.getNumChildren() == 1) {
|
||||
if (expression.getChild(0) instanceof ASTPrimaryExpression) {
|
||||
primaryExpression = expression.getChild(0);
|
||||
} else if (expression.getChild(0) instanceof ASTCastExpression
|
||||
&& expression.getChild(0).getChild(1) instanceof ASTPrimaryExpression) {
|
||||
primaryExpression = expression.getChild(0).getChild(1);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
final Node primaryPrefix = primaryExpression.getChild(0);
|
||||
if (primaryPrefix.getNumChildren() == 1 && primaryPrefix.getChild(0) instanceof ASTLiteral) {
|
||||
final ASTLiteral literal = (ASTLiteral) primaryPrefix.getChild(0);
|
||||
if (isRef(fieldDeclaration, variableDeclarator)) {
|
||||
// Reference type
|
||||
if (literal.getNumChildren() == 1 && literal.getChild(0) instanceof ASTNullLiteral) {
|
||||
addViolation(data, variableDeclarator);
|
||||
}
|
||||
} else {
|
||||
// Primitive type
|
||||
if (literal.getNumChildren() == 1
|
||||
&& literal.getChild(0) instanceof ASTBooleanLiteral) {
|
||||
// boolean type
|
||||
ASTBooleanLiteral booleanLiteral = (ASTBooleanLiteral) literal.getChild(0);
|
||||
if (!booleanLiteral.isTrue()) {
|
||||
addViolation(data, variableDeclarator);
|
||||
}
|
||||
} else if (literal.getNumChildren() == 0) {
|
||||
// numeric type
|
||||
// Note: Not catching NumberFormatException, as
|
||||
// it shouldn't be happening on valid source
|
||||
// code.
|
||||
Number value = -1;
|
||||
if (literal.isIntLiteral()) {
|
||||
value = literal.getValueAsInt();
|
||||
} else if (literal.isLongLiteral()) {
|
||||
value = literal.getValueAsLong();
|
||||
} else if (literal.isFloatLiteral()) {
|
||||
value = literal.getValueAsFloat();
|
||||
} else if (literal.isDoubleLiteral()) {
|
||||
value = literal.getValueAsDouble();
|
||||
} else if (literal.isCharLiteral()) {
|
||||
value = (int) literal.getImage().charAt(1);
|
||||
}
|
||||
|
||||
if (value.doubleValue() == 0) {
|
||||
addViolation(data, variableDeclarator);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (declaresNotFinalField(fieldDeclaration)) {
|
||||
List<ASTVariableDeclarator> varDecls = fieldDeclaration.findDescendantsOfType(ASTVariableDeclarator.class);
|
||||
for (ASTVariableDeclarator varDecl : varDecls) {
|
||||
if (hasRedundantInitializer(fieldDeclaration, varDecl)) {
|
||||
addViolation(data, varDecl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a FieldDeclaration is a reference type (includes arrays). The
|
||||
* reference information is in the FieldDeclaration for this example:
|
||||
*
|
||||
* <pre>
|
||||
* int[] ia1
|
||||
* </pre>
|
||||
*
|
||||
* and in the VariableDeclarator for this example:
|
||||
*
|
||||
* <pre>
|
||||
* int ia2[];
|
||||
* </pre>
|
||||
*
|
||||
* .
|
||||
*
|
||||
* @param fieldDeclaration
|
||||
* the field to check.
|
||||
* @param variableDeclarator
|
||||
* the variable declarator to check.
|
||||
* @return <code>true</code> if the field is a reference. <code>false</code>
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean isRef(ASTFieldDeclaration fieldDeclaration, ASTVariableDeclarator variableDeclarator) {
|
||||
Node type = fieldDeclaration.getChild(0).getChild(0);
|
||||
if (type instanceof ASTReferenceType) {
|
||||
// Reference type, array or otherwise
|
||||
return true;
|
||||
} else {
|
||||
// Primitive array?
|
||||
return ((ASTVariableDeclaratorId) variableDeclarator.getChild(0)).isArray();
|
||||
}
|
||||
private boolean declaresNotFinalField(ASTFieldDeclaration fieldDeclaration) {
|
||||
return !fieldDeclaration.isFinal();
|
||||
}
|
||||
|
||||
private void addViolation(Object data, ASTVariableDeclarator variableDeclarator) {
|
||||
super.addViolation(data, variableDeclarator, variableDeclarator.getChild(0).getImage());
|
||||
private boolean hasRedundantInitializer(ASTFieldDeclaration fieldDeclaration, ASTVariableDeclarator varDecl) {
|
||||
return declaresFieldOfPrimitiveType(fieldDeclaration)
|
||||
&& hasRedundantInitializerOfPrimitive(varDecl)
|
||||
|| hasRedundantInitializerOfReference(varDecl);
|
||||
}
|
||||
|
||||
private boolean declaresFieldOfPrimitiveType(ASTFieldDeclaration fieldDeclaration) {
|
||||
return fieldDeclaration.getChild(0).getChild(0) instanceof ASTPrimitiveType;
|
||||
}
|
||||
|
||||
private boolean hasRedundantInitializerOfPrimitive(ASTVariableDeclarator varDecl) {
|
||||
ASTLiteral literal = getLiteralValue(varDecl);
|
||||
if (literal != null) {
|
||||
if (isNumericLiteral(literal)) {
|
||||
return getNumericLiteralValue(literal) == 0;
|
||||
}
|
||||
if (literal.isCharLiteral()) {
|
||||
return hasDefaultCharLiteralValue(literal);
|
||||
}
|
||||
return isDefaultBooleanLiteral(literal);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isNumericLiteral(ASTLiteral literal) {
|
||||
return literal.isIntLiteral() || literal.isLongLiteral()
|
||||
|| literal.isFloatLiteral() || literal.isDoubleLiteral();
|
||||
}
|
||||
|
||||
private double getNumericLiteralValue(ASTLiteral literal) {
|
||||
if (literal.isIntLiteral()) {
|
||||
return literal.getValueAsInt();
|
||||
}
|
||||
if (literal.isLongLiteral()) {
|
||||
return literal.getValueAsLong();
|
||||
}
|
||||
if (literal.isFloatLiteral()) {
|
||||
return literal.getValueAsFloat();
|
||||
}
|
||||
return literal.getValueAsDouble();
|
||||
}
|
||||
|
||||
private boolean hasDefaultCharLiteralValue(ASTLiteral literal) {
|
||||
String img = literal.getImage();
|
||||
return img.contains("\u0000") || img.contains("\\0");
|
||||
}
|
||||
|
||||
private boolean isDefaultBooleanLiteral(ASTLiteral literal) {
|
||||
ASTBooleanLiteral booleanLiteral = literal.getFirstDescendantOfType(ASTBooleanLiteral.class);
|
||||
return booleanLiteral != null && !booleanLiteral.isTrue();
|
||||
}
|
||||
|
||||
private boolean hasRedundantInitializerOfReference(ASTVariableDeclarator varDecl) {
|
||||
ASTLiteral literal = getLiteralValue(varDecl);
|
||||
return literal != null && isNullLiteral(literal);
|
||||
}
|
||||
|
||||
private ASTLiteral getLiteralValue(ASTVariableDeclarator varDecl) {
|
||||
ASTPrimaryPrefix prefix = varDecl.getFirstDescendantOfType(ASTPrimaryPrefix.class);
|
||||
return prefix != null && prefix.getNumChildren() == 1
|
||||
? prefix.getFirstChildOfType(ASTLiteral.class)
|
||||
: null;
|
||||
}
|
||||
|
||||
private boolean isNullLiteral(ASTLiteral literal) {
|
||||
return literal.getFirstDescendantOfType(ASTNullLiteral.class) != null;
|
||||
}
|
||||
}
|
||||
+11
@@ -1431,6 +1431,17 @@ public class Test {
|
||||
public class RedundantFieldInitializerTest {
|
||||
private long hexLongMinusOne = 0xffffffffffffffffL;
|
||||
private int hexIntMinusOne = 0xffffffff;
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#2441 can not detect a case char c = '\0';</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>2</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
char c = '\0';
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
Reference in new issue
Block a user