[javascript] Correctly determine double inaccuracy

Fixes #4716
This commit is contained in:
Andreas Dangel 2024-07-19 13:18:10 +02:00
parent 18c1ffc165
commit b176ca72c1
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
5 changed files with 44 additions and 2 deletions

View File

@ -34,6 +34,8 @@ This is a {{ site.pmd.release_type }} release.
* [#4800](https://github.com/pmd/pmd/issues/4800): \[apex] ClassNamingConvention: Support naming convention for *inner* classes
* apex-performance
* [#635](https://github.com/pmd/pmd/issues/635): \[apex] New Rule: Avoid soql/sosl queries without a where clause or limit statement
* javascript-errorprone
* [#4716](https://github.com/pmd/pmd/issues/4716): \[javascript] InaccurateNumericLiteral with number 259200000
* plsql
* [#5086](https://github.com/pmd/pmd/pull/5086): \[plsql] Fixed issue with missing optional table alias in MERGE usage
* [#5087](https://github.com/pmd/pmd/pull/5087): \[plsql] Add support for SQL_MACRO

View File

@ -109,7 +109,7 @@ public final class XPathRule extends AbstractRule {
// Nodes might already have been refactored to not use getImage anymore.
// Therefore, try several other common names
if (messageArg == null) {
messageArg = getFirstMessageArgFromNode(nodeWithViolation, "Name", "SimpleName", "MethodName");
messageArg = getFirstMessageArgFromNode(nodeWithViolation, "Name", "SimpleName", "MethodName", "Value");
}
ctx.addViolation(nodeWithViolation, messageArg);
}

View File

@ -4,6 +4,8 @@
package net.sourceforge.pmd.lang.ecmascript.ast;
import java.math.BigDecimal;
import org.mozilla.javascript.ast.NumberLiteral;
public final class ASTNumberLiteral extends AbstractEcmascriptNode<NumberLiteral> {
@ -57,4 +59,16 @@ public final class ASTNumberLiteral extends AbstractEcmascriptNode<NumberLiteral
public String getValue() {
return node.getValue();
}
/**
* Checks if this number literal cannot be represented exactly without loss as
* a JavaScript Number. The number is either too big or uses too many decimal places.
* @return {@code true} if the literal is inaccurate.
* @since 7.4.0
*/
public boolean isInaccurate() {
BigDecimal bigDecimal = new BigDecimal(getNormalizedImage());
BigDecimal converted = BigDecimal.valueOf(bigDecimal.doubleValue());
return bigDecimal.compareTo(converted) != 0;
}
}

View File

@ -100,13 +100,19 @@ if (someVar != 3) {
<description>
The numeric literal will have a different value at runtime, which can happen if you provide too much
precision in a floating point number. This may result in numeric calculations being in error.
[Numbers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) in JavaScript
are represented by 64bit double-precision floating point numbers internally and that's why there are some limits
to the available precision of the number.
See [Number.isSafeInteger()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isSafeInteger)
and [Number.EPSILON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON).
</description>
<priority>2</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//NumberLiteral[@NormalizedImage != string(@Number)]
//NumberLiteral[@Inaccurate = true()]
]]>
</value>
</property>

View File

@ -9,12 +9,17 @@
<expected-problems>0</expected-problems>
<code><![CDATA[
var x = 1;
var a = 9; // Ok
var b = 999999999999999; // Ok
]]></code>
</test-code>
<test-code>
<description>Bad integer</description>
<expected-problems>1</expected-problems>
<expected-messages>
<message>The numeric literal '999999999999999999999999' will have at different value at runtime.</message>
</expected-messages>
<code>var x = 999999999999999999999999;</code>
</test-code>
@ -45,6 +50,9 @@ var x = 1.12e-4;
<test-code>
<description>Bad float w/ exponent</description>
<expected-problems>1</expected-problems>
<expected-messages>
<message>The numeric literal '1.12345678901234567e-4' will have at different value at runtime.</message>
</expected-messages>
<code><![CDATA[
var x = 1.12345678901234567e-4;
]]></code>
@ -69,6 +77,18 @@ const value2 = 0b1010_0001_1000_0101; // binary
const value3 = 0xA0_B0; // hex
const value4 = 9_223_372_036_854_775_807n; // big int
const value5 = 0o1234_5670; // octal
]]></code>
</test-code>
<test-code>
<description>#4716 [javascript] InaccurateNumericLiteral with number 259200000</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
const USER_LIST_TRANSACTION_EXP_MS_1 = 259200000;
var USER_LIST_TRANSACTION_EXP_MS_2 = 259200000;
// big int primitives: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
const hugeBigInt = 129007199254740991n;
]]></code>
</test-code>
</test-data>