SONARJAVA-6743 Implement new rule S9147: "NaN" should not be tested for equality using "==" or "!=" - #5908
SONARJAVA-6743 Implement new rule S9147: "NaN" should not be tested for equality using "==" or "!="#5908romainbrenguier wants to merge 2 commits into
Conversation
Detect equality and inequality comparisons (== and !=) with Double.NaN and Float.NaN constants, which always produce incorrect results due to IEEE 754 semantics. Suggests using Double.isNaN() or Float.isNaN() instead.
| if (expr.is(Tree.Kind.MEMBER_SELECT)) { | ||
| MemberSelectExpressionTree memberSelect = (MemberSelectExpressionTree) expr; | ||
| if ("NaN".equals(memberSelect.identifier().name())) { | ||
| String ownerType = memberSelect.identifier().symbol().owner().type().fullyQualifiedName(); |
There was a problem hiding this comment.
⚠️ Bug: Possible NPE on unknown symbol owner in getNanTypeName
memberSelect.identifier().symbol().owner().type().fullyQualifiedName() chains through owner(), which is declared @Nullable (returns null for package/unknown symbols per the Symbol interface contract). When the NaN identifier's symbol cannot be resolved (e.g. incomplete classpath/semantics), this can throw a NullPointerException, causing the check to fail on that file. Guard against unresolved symbols before dereferencing. Note similar checks (e.g. SillyEqualsCheck) use isUnknown() guards.
Bail out when the symbol is unknown or its owner is null before dereferencing.:
if ("NaN".equals(memberSelect.identifier().name())) {
Symbol symbol = memberSelect.identifier().symbol();
Symbol owner = symbol.owner();
if (symbol.isUnknown() || owner == null) {
return null;
}
String ownerType = owner.type().fullyQualifiedName();
if ("java.lang.Double".equals(ownerType)) {
return "Double";
}
if ("java.lang.Float".equals(ownerType)) {
return "Float";
}
}
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
| if (expr.is(Tree.Kind.MEMBER_SELECT)) { | ||
| MemberSelectExpressionTree memberSelect = (MemberSelectExpressionTree) expr; | ||
| if ("NaN".equals(memberSelect.identifier().name())) { | ||
| String ownerType = memberSelect.identifier().symbol().owner().type().fullyQualifiedName(); | ||
| if ("java.lang.Double".equals(ownerType)) { | ||
| return "Double"; | ||
| } | ||
| if ("java.lang.Float".equals(ownerType)) { | ||
| return "Float"; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
💡 Edge Case: Static-imported NaN not detected (MEMBER_SELECT-only match)
getNanTypeName only matches when the operand is a MEMBER_SELECT (e.g. Double.NaN). Code using import static java.lang.Double.NaN; and referencing bare NaN yields an IDENTIFIER node and is silently missed (false negative). Consider also handling identifier references whose symbol owner is java.lang.Double/Float, or document this limitation.
Was this helpful? React with 👍 / 👎
|
❌ Ruling needs updating. A fix PR has been created: #5909 Please review and merge it into your branch. |
CI failed: Integration and ruling tests failed due to test output mismatches for the new rule S9147 and a Windows file access error during scanner cache movement.OverviewAnalysis of 3 CI logs revealed 2 distinct test and execution failures related to the implementation of new rule S9147 ("NaN" should not be tested for equality using "==" or "!="). Specifically, integration/autoscan diff expectations require updating to match the new rule outputs, and a Windows runner encountered a file locking/access denial when caching SonarScanner engine files. FailuresRuling and Autoscan Test Output Mismatches (confidence: high)
Windows Scanner Cache Access Denied Error (confidence: high)
Summary
Code Review
|
| Auto-apply | Compact | Unblock |
|
|
|
Was this helpful? React with 👍 / 👎 | Gitar
|




Detect equality and inequality comparisons (== and !=) with Double.NaN and Float.NaN constants, which always produce incorrect results due to IEEE 754 semantics. Suggests using Double.isNaN() or Float.isNaN() instead.