Merge pull request #3386 from adangel:pmd7-update-BigIntegerInstantiation

[java] Update BigIntegerInstantiation #3386
This commit is contained in:
Andreas Dangel committed 2021-07-16 10:33:36 +02:00
commit 55309f0ead
5 files changed
+98 -53

No files matched your search

+1 -1
View File
@@ -291,7 +291,7 @@
<rule ref="category/java/performance.xml/AvoidFileStream"/>
<!-- <rule ref="category/java/performance.xml/AvoidInstantiatingObjectsInLoops"/> -->
<rule ref="category/java/performance.xml/AvoidUsingShortType"/>
<!-- <rule ref="category/java/performance.xml/BigIntegerInstantiation"/> -->
<rule ref="category/java/performance.xml/BigIntegerInstantiation"/>
<!-- <rule ref="category/java/performance.xml/BooleanInstantiation"/> -->
<rule ref="category/java/performance.xml/ByteInstantiation"/>
<rule ref="category/java/performance.xml/ConsecutiveAppendsShouldReuse"/>
@@ -6,57 +6,56 @@ package net.sourceforge.pmd.lang.java.rule.performance;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Set;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.JavaLanguageModule;
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
import net.sourceforge.pmd.util.CollectionUtil;
/**
* Rule that marks instantiations of new {@link BigInteger} or
* {@link BigDecimal} objects, when there is a well-known constant available,
* such as {@link BigInteger#ZERO}.
* Rule that marks instantiations of new {@link BigInteger} or {@link BigDecimal} objects, when there is a well-known
* constant available, such as {@link BigInteger#ZERO}.
*/
public class BigIntegerInstantiationRule extends AbstractJavaRule {
public class BigIntegerInstantiationRule extends AbstractJavaRulechainRule {
private static final Set<String> CONSTANTS = CollectionUtil.setOf("0", "0.", "1");
public BigIntegerInstantiationRule() {
super(ASTConstructorCall.class);
}
@Override
public Object visit(ASTAllocationExpression node, Object data) {
Node type = node.getChild(0);
public Object visit(ASTConstructorCall node, Object data) {
LanguageVersion languageVersion = node.getAstInfo().getLanguageVersion();
boolean jdk15 = languageVersion.compareToVersion("1.5") >= 0;
boolean jdk9 = languageVersion.compareToVersion("9") >= 0;
if (!(type instanceof ASTClassOrInterfaceType)) {
return super.visit(node, data);
}
if (TypeTestUtil.isA(BigInteger.class, node) || jdk15 && TypeTestUtil.isA(BigDecimal.class, node)) {
boolean jdk15 = node.getAstInfo().getLanguageVersion().compareTo(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5")) >= 0;
if ((TypeTestUtil.isA(BigInteger.class, (ASTClassOrInterfaceType) type)
|| jdk15 && TypeTestUtil.isA(BigDecimal.class, (ASTClassOrInterfaceType) type))
&& !node.hasDescendantOfType(ASTArrayDimsAndInits.class)) {
ASTArguments args = node.getFirstChildOfType(ASTArguments.class);
if (args.size() == 1) {
ASTLiteral literal = node.getFirstDescendantOfType(ASTLiteral.class);
if (literal == null
|| literal.getParent().getParent().getParent().getParent().getParent() != args) {
return super.visit(node, data);
}
@NonNull
ASTArgumentList arguments = node.getArguments();
if (arguments.size() == 1) {
ASTExpression firstArg = arguments.get(0);
String img = literal.getImage();
if (literal.isStringLiteral()) {
img = img.substring(1, img.length() - 1);
}
if ("0".equals(img) || "1".equals(img) || jdk15 && "10".equals(img)) {
Object constValue = firstArg.getConstValue();
if (CONSTANTS.contains(constValue)
|| jdk15 && "10".equals(constValue)
|| jdk9 && "2".equals(constValue)
|| Integer.valueOf(0).equals(constValue)
|| Integer.valueOf(1).equals(constValue)
|| jdk15 && Integer.valueOf(10).equals(constValue)) {
addViolation(data, node);
return data;
}
}
}
return super.visit(node, data);
return data;
}
}
@@ -313,21 +313,25 @@ public class UsingShort {
<rule name="BigIntegerInstantiation"
language="java"
since="3.9"
message="Don't create instances of already existing BigInteger and BigDecimal (ZERO, ONE, TEN)"
message="Don''t create instances of already existing BigInteger and BigDecimal (ZERO, ONE, TEN)"
class="net.sourceforge.pmd.lang.java.rule.performance.BigIntegerInstantiationRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#bigintegerinstantiation">
<description>
Don't create instances of already existing BigInteger (BigInteger.ZERO, BigInteger.ONE) and
for Java 1.5 onwards, BigInteger.TEN and BigDecimal (BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN)
Don't create instances of already existing BigInteger (`BigInteger.ZERO`, `BigInteger.ONE`),
for Java 1.5 onwards, BigInteger.TEN and BigDecimal (`BigDecimal.ZERO`, `BigDecimal.ONE`, `BigDecimal.TEN`) and
for Java 9 onwards `BigInteger.TWO`.
</description>
<priority>3</priority>
<example>
<![CDATA[
BigInteger bi = new BigInteger(1); // reference BigInteger.ONE instead
BigInteger bi1 = new BigInteger("1"); // reference BigInteger.ONE instead
BigInteger bi2 = new BigInteger("0"); // reference BigInteger.ZERO instead
BigInteger bi3 = new BigInteger(0.0); // reference BigInteger.ZERO instead
BigInteger bi4;
bi4 = new BigInteger(0); // reference BigInteger.ZERO instead
BigInteger bi3;
bi3 = new BigInteger("0"); // reference BigInteger.ZERO instead
BigDecimal bd1 = new BigDecimal(0); // reference BigDecimal.ZERO instead
BigDecimal bd2 = new BigDecimal("0.") ; // reference BigDecimal.ZERO instead
BigDecimal bd3 = new BigDecimal(10); // reference BigDecimal.TEN instead
]]>
</example>
</rule>
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.performance;
import net.sourceforge.pmd.testframework.PmdRuleTst;
@org.junit.Ignore("Rule has not been updated yet")
public class BigIntegerInstantiationTest extends PmdRuleTst {
// no additional unit tests
}
@@ -7,6 +7,7 @@
<test-code>
<description>Fail, BigInteger(1)</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
import java.math.BigInteger;
@@ -33,6 +34,7 @@ public class Foo {
<test-code>
<description>Fail, BigInteger(0)</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
import java.math.BigInteger;
@@ -83,6 +85,7 @@ public class Foo {
<test-code>
<description>Fail, BigInteger(10) 1.5 mode</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
import java.math.BigInteger;
@@ -95,12 +98,14 @@ public class Foo {
<test-code>
<description>Fail, BigDecimal(1)</description>
<expected-problems>1</expected-problems>
<expected-problems>2</expected-problems>
<expected-linenumbers>4,5</expected-linenumbers>
<code><![CDATA[
import java.math.BigDecimal;
public class Foo {
BigDecimal b = new BigDecimal(1);
BigDecimal b1 = new BigDecimal(1);
BigDecimal b2 = new BigDecimal("1");
}
]]></code>
<source-type>java 1.5</source-type>
@@ -108,12 +113,14 @@ public class Foo {
<test-code>
<description>Fail, BigDecimal(10)</description>
<expected-problems>1</expected-problems>
<expected-problems>2</expected-problems>
<expected-linenumbers>4,5</expected-linenumbers>
<code><![CDATA[
import java.math.BigDecimal;
public class Foo {
BigDecimal b = new BigDecimal(10);
BigDecimal b1 = new BigDecimal(10);
BigDecimal b2 = new BigDecimal("10");
}
]]></code>
<source-type>java 1.5</source-type>
@@ -121,14 +128,50 @@ public class Foo {
<test-code>
<description>Fail, BigDecimal(0)</description>
<expected-problems>1</expected-problems>
<expected-problems>3</expected-problems>
<expected-linenumbers>4,5,6</expected-linenumbers>
<code><![CDATA[
import java.math.BigDecimal;
public class Foo {
BigDecimal b = new BigDecimal(0);
BigDecimal b1 = new BigDecimal(0);
BigDecimal b2 = new BigDecimal("0");
BigDecimal b3 = new BigDecimal("0.");
BigDecimal b4 = new BigDecimal("0.0"); // that's not ZERO - ZERO has no decimals, this has 1 decimal (scale)
}
]]></code>
<source-type>java 1.5</source-type>
</test-code>
<test-code>
<description>Fail, BigInteger(2) with Java9</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
import java.math.BigInteger;
public class Foo {
BigInteger b = new BigInteger("2"); // Use BigInteger.TWO instead
}
]]></code>
<source-type>java 9</source-type>
</test-code>
<test-code>
<description>False negative with indirect const string</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>5</expected-linenumbers>
<code><![CDATA[
import java.math.BigInteger;
class Foo {
static final String Z = "0";
static { new BigInteger(Z); }
public void test(String a) {
new BigInteger(a); // not a const value
}
}
]]></code>
</test-code>
</test-data>