Merge branch 'pr-849'

Closes #841
This commit is contained in:
Andreas Dangel
2018-01-15 20:44:50 +01:00
6 changed files with 130 additions and 47 deletions

View File

@ -62,6 +62,8 @@ at <https://pmd.github.io/latest/>.
* [#817](https://github.com/pmd/pmd/issues/817): \[java] UnnecessaryModifierRule crashes on valid code
* java-design
* [#785](https://github.com/pmd/pmd/issues/785): \[java] NPE in DataClass rule
* java-performance
* [#841](https://github.com/pmd/pmd/issues/841): \[java] InsufficientStringBufferDeclaration NumberFormatException
### API Changes

View File

@ -96,6 +96,69 @@ public class ASTLiteral extends AbstractJavaTypeNode {
}
return false;
}
private String stripIntValue() {
String image = getImage().toLowerCase().replaceAll("_", "");
boolean isNegative = false;
if (image.charAt(0) == '-') {
isNegative = true;
image = image.substring(1);
}
if (image.endsWith("l")) {
image = image.substring(0, image.length() - 1);
}
// ignore base prefix if any
if (image.charAt(0) == '0' && image.length() > 1) {
if (image.charAt(1) == 'x' || image.charAt(1) == 'b') {
image = image.substring(2);
} else {
image = image.substring(1);
}
}
if (isNegative) {
return "-" + image;
}
return image;
}
private String stripFloatValue() {
return getImage().toLowerCase().replaceAll("_", "");
}
private int getIntBase() {
final String image = getImage().toLowerCase();
final int offset = image.charAt(0) == '-' ? 1 : 0;
if (image.startsWith("0x", offset)) {
return 16;
}
if (image.startsWith("0b", offset)) {
return 2;
}
if (image.startsWith("0", offset) && image.length() > 1) {
return 8;
}
return 10;
}
public int getValueAsInt() {
return (int) getValueAsLong(); // the downcast allows to parse 0x80000000+ numbers as negative instead of a NumberFormatException
}
public long getValueAsLong() {
return Long.parseLong(stripIntValue(), getIntBase());
}
public float getValueAsFloat() {
return Float.parseFloat(stripFloatValue());
}
public double getValueAsDouble() {
return Double.parseDouble(stripFloatValue());
}
public void setCharLiteral() {
this.isChar = true;

View File

@ -199,16 +199,17 @@ public class InsufficientStringBufferDeclarationRule extends AbstractJavaRule {
anticipatedLength += str.length() - 2;
} else if (literal.isCharLiteral()) {
anticipatedLength += 1;
} else if (literal.isIntLiteral() && str.startsWith("0x")) {
} else if (literal.isIntLiteral()) {
// but only if we are not inside a cast expression
Node parentNode = literal.jjtGetParent().jjtGetParent().jjtGetParent();
if (parentNode instanceof ASTCastExpression
&& ((ASTCastExpression) parentNode).getType() == char.class) {
anticipatedLength += 1;
} else {
// any number, regardless of the base will be converted to base 10
// e.g. 0xdeadbeef -> will be converted to a
// base 10 integer string: 3735928559
anticipatedLength += String.valueOf(Long.parseLong(str.substring(2), 16)).length();
anticipatedLength += String.valueOf(literal.getValueAsLong()).length();
}
} else {
anticipatedLength += str.length();
@ -273,11 +274,8 @@ public class InsufficientStringBufferDeclarationRule extends AbstractJavaRule {
// characters
// don't add the constructor's length
iConstructorLength = 14 + str.length();
} else if (literal.isIntLiteral() && str.startsWith("0x")) {
// bug 3516101 - the string could be a hex number
iConstructorLength = Integer.parseInt(str.substring(2), 16);
} else {
iConstructorLength = Integer.parseInt(str);
} else if (literal.isIntLiteral()) {
iConstructorLength = literal.getValueAsInt();
}
} else {
iConstructorLength = -1;

View File

@ -4,8 +4,6 @@
package net.sourceforge.pmd.lang.java.rule.performance;
import java.math.BigInteger;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTCastExpression;
@ -83,21 +81,13 @@ public class RedundantFieldInitializerRule extends AbstractJavaRule {
// code.
Number value = -1;
if (literal.isIntLiteral()) {
value = parseInteger(literal.getImage());
value = literal.getValueAsInt();
} else if (literal.isLongLiteral()) {
String s = literal.getImage();
// remove the ending "l" or "L" for long
// values
s = s.substring(0, s.length() - 1);
value = parseInteger(s);
value = literal.getValueAsLong();
} else if (literal.isFloatLiteral()) {
String s = literal.getImage();
// remove the ending "f" or "F" for float
// values
s = s.substring(0, s.length() - 1);
value = Float.valueOf(s.replaceAll("_", ""));
value = literal.getValueAsFloat();
} else if (literal.isDoubleLiteral()) {
value = Double.valueOf(literal.getImage().replaceAll("_", ""));
value = literal.getValueAsDouble();
} else if (literal.isCharLiteral()) {
value = (int) literal.getImage().charAt(1);
}
@ -152,27 +142,4 @@ public class RedundantFieldInitializerRule extends AbstractJavaRule {
private void addViolation(Object data, ASTVariableDeclarator variableDeclarator) {
super.addViolation(data, variableDeclarator, variableDeclarator.jjtGetChild(0).getImage());
}
private Number parseInteger(String s) {
boolean negative = false;
String number = s;
if (number.charAt(0) == '-') {
negative = true;
number = number.substring(1);
}
BigInteger result;
if (number.startsWith("0x") || number.startsWith("0X")) {
result = new BigInteger(number.substring(2).replaceAll("_", ""), 16);
} else if (number.startsWith("0b") || number.startsWith("0B")) {
result = new BigInteger(number.substring(2).replaceAll("_", ""), 8);
} else if (number.charAt(0) == '0' && number.length() > 1) {
result = new BigInteger(number.substring(1).replaceAll("_", ""), 8);
} else {
result = new BigInteger(number.replaceAll("_", ""));
}
if (negative) {
result = result.negate();
}
return result;
}
}

View File

@ -59,6 +59,46 @@ public class ASTLiteralTest {
assertTrue((literals.iterator().next()).isCharLiteral());
}
@Test
public void testIntValueParsing() {
ASTLiteral literal = new ASTLiteral(1);
literal.setIntLiteral();
literal.setImage("1___234");
literal.testingOnlySetBeginColumn(1);
literal.testingOnlySetEndColumn(7);
assertEquals(1234, literal.getValueAsInt());
}
@Test
public void testIntValueParsingBinary() {
ASTLiteral literal = new ASTLiteral(1);
literal.setIntLiteral();
literal.setImage("0b0000_0010");
literal.testingOnlySetBeginColumn(1);
literal.testingOnlySetEndColumn(7);
assertEquals(2, literal.getValueAsInt());
}
@Test
public void testIntValueParsingNegativeHexa() {
ASTLiteral literal = new ASTLiteral(1);
literal.setIntLiteral();
literal.setImage("-0X0000_000f");
literal.testingOnlySetBeginColumn(1);
literal.testingOnlySetEndColumn(7);
assertEquals(-15, literal.getValueAsInt());
}
@Test
public void testFloatValueParsingNegative() {
ASTLiteral literal = new ASTLiteral(1);
literal.setIntLiteral();
literal.setImage("-3_456.123_456");
literal.testingOnlySetBeginColumn(1);
literal.testingOnlySetEndColumn(7);
assertEquals(-3456.123456f, literal.getValueAsFloat(), 0);
}
@Test
public void testStringUnicodeEscapesNotEscaped() {
ASTLiteral literal = new ASTLiteral(1);

View File

@ -310,7 +310,7 @@ public class Foo {
</test-code>
<test-code>
<description><![CDATA[
15, Append int, incorrect presize
15, Append long, incorrect presize
]]></description>
<expected-problems>2</expected-problems>
<code><![CDATA[
@ -318,11 +318,11 @@ public class Foo {
private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(Foo.class);
public void bar() {
StringBuffer sb = new StringBuffer();
sb.append(12345678901234567890);
sb.append(12345678901234567890L);
}
public void bar2() {
StringBuilder sb = new StringBuilder();
sb.append(12345678901234567890);
sb.append(12345678901234567890L);
}
}
]]></code>
@ -1059,6 +1059,19 @@ public final class test {
"# Testing" + NEWLINE +
"# More Contents" + NEWLINE);
}
}
]]></code>
</test-code>
<test-code>
<description>#841 InsufficientStringBufferDeclaration NumberFormatException</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Test {
public static void main(final String ... args) {
StringBuilder report = new StringBuilder(10_000).append("test");
}
}
]]></code>
</test-code>