Skip to content

SONARJAVA-6703 Implement new rule S9133 - #5862

Open
romainbrenguier wants to merge 6 commits into
masterfrom
new-rule/SONARJAVA-6703-S9133
Open

SONARJAVA-6703 Implement new rule S9133#5862
romainbrenguier wants to merge 6 commits into
masterfrom
new-rule/SONARJAVA-6703-S9133

Conversation

@romainbrenguier

Copy link
Copy Markdown
Contributor

Detect hard-coded floating-point literals that approximate well-known mathematical constants (pi, e, sqrt(2), ln(2)) and suggest using the corresponding Math class constants or expressions instead.

Part of

Detect hard-coded floating-point literals that approximate well-known
mathematical constants (pi, e, sqrt(2), ln(2)) and suggest using the
corresponding Math class constants or expressions instead.
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

SONARJAVA-6703

Comment thread java-checks/src/main/java/org/sonar/java/checks/HardcodedMathConstantCheck.java Outdated
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Ruling needs updating. A fix PR has been created: #5863

Please review and merge it into your branch.

romainbrenguier pushed a commit that referenced this pull request Aug 3, 2026
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Ruling Diff Summary

Detected changes in 1 rule files: 0 issues removed, 18 issues added.

S9133 (java) on sonar-server - 0 issues removed, 18 issues added - new ruling file

Added src/test/java/org/sonar/server/computation/task/projectanalysis/issue/TrackerRawInputFactoryTest.java (line 103)

(source file not found at this revision: src/test/java/org/sonar/server/computation/task/projectanalysis/issue/TrackerRawInputFactoryTest.java)

Added src/test/java/org/sonar/server/computation/task/projectanalysis/issue/TrackerRawInputFactoryTest.java (line 116)

(source file not found at this revision: src/test/java/org/sonar/server/computation/task/projectanalysis/issue/TrackerRawInputFactoryTest.java)

Added src/test/java/org/sonar/server/computation/task/projectanalysis/issue/TrackerRawInputFactoryTest.java (line 117)

(source file not found at this revision: src/test/java/org/sonar/server/computation/task/projectanalysis/issue/TrackerRawInputFactoryTest.java)

Added src/test/java/org/sonar/server/computation/task/projectanalysis/step/CustomMeasuresCopyStepTest.java (line 106)

(source file not found at this revision: src/test/java/org/sonar/server/computation/task/projectanalysis/step/CustomMeasuresCopyStepTest.java)

Added src/test/java/org/sonar/server/computation/task/projectanalysis/step/CustomMeasuresCopyStepTest.java (line 144)

(source file not found at this revision: src/test/java/org/sonar/server/computation/task/projectanalysis/step/CustomMeasuresCopyStepTest.java)

Added src/test/java/org/sonar/server/issue/IssueDocTesting.java (line 43)

(source file not found at this revision: src/test/java/org/sonar/server/issue/IssueDocTesting.java)

Added src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java (line 352)

(source file not found at this revision: src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java)

Added src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java (line 355)

(source file not found at this revision: src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java)

Added src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java (line 361)

(source file not found at this revision: src/test/java/org/sonar/server/issue/IssueFieldsSetterTest.java)

Added src/test/java/org/sonar/server/measure/custom/ws/CustomMeasureValidatorTest.java (line 73)

(source file not found at this revision: src/test/java/org/sonar/server/measure/custom/ws/CustomMeasureValidatorTest.java)

Added src/test/java/org/sonar/server/util/RubyUtilsTest.java (line 91)

(source file not found at this revision: src/test/java/org/sonar/server/util/RubyUtilsTest.java)

Added src/test/java/org/sonar/server/util/RubyUtilsTest.java (line 92)

(source file not found at this revision: src/test/java/org/sonar/server/util/RubyUtilsTest.java)

Replace fixed relative tolerance with dynamic precision-based tolerance
derived from the literal's significant digit count. Raise minimum
significant digits from 3 to 4 to avoid false positives on common
domain values like 0.693. Add test cases for underscore-separated
literals, D/d suffixes, leading-dot literals, and zero value.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@romainbrenguier
romainbrenguier force-pushed the new-rule/SONARJAVA-6703-S9133 branch from 4925f8b to 0c2cf07 Compare August 3, 2026 13:49
Remove unreachable '-' and '+' handling from countSignificantDigits
since Java literal tokens never contain sign characters. Add test
cases for uppercase 'E' scientific notation, '0X' hex prefix, 'F'
float suffix, and leading-dot noncompliant literal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@romainbrenguier
romainbrenguier marked this pull request as ready for review August 4, 2026 06:13

@rombirli rombirli left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rule looks good, but a few things should be improved :

  • support octal/binary bases
  • what happens with negative numbers?
  • some functions could be rewritten in an easier way, less verbose

@Rule(key = "S9133")
public class HardcodedMathConstantCheck extends IssuableSubscriptionVisitor {

private static final int MIN_SIGNIFICANT_DIGITS = 4;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most commonly used approximation of pi is 3.14, which has only 3 significant digits, i would set it to 3

value = value.substring(0, value.length() - 1);
}
// Skip hex float literals
if (value.startsWith("0x") || value.startsWith("0X")) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should extend to binary values (0b) and octal values (leading 0)

}
return count;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks to be incorrect on negative numbers at first sight, the reproducer should contain a negative nubmer case to verify

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could also be rewritten in a easier-to-understand way :

private static int countSignificantDigits(String normalized) {
    String sig = normalized.replace("-", "").replace(".", "").replaceFirst("^0+", "");
    return sig.isEmpty() ? 1 : sig.length();
}

String value = rawValue.replace("_", "");
// Strip type suffix
char last = value.charAt(value.length() - 1);
if (last == 'f' || last == 'F' || last == 'd' || last == 'D') {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about

if ("fd".contains(last.toLowerCase())) { ... 

- Lower MIN_SIGNIFICANT_DIGITS from 4 to 3 to catch common approximations like 3.14
- Add support for skipping binary (0b) and octal (leading 0) literals in normalize()
- Simplify suffix stripping using "fd".indexOf(Character.toLowerCase())
- Rewrite countSignificantDigits with simpler string operations
- Add negative number test cases to verify unary minus handling
- Update test expectations for new 3-digit threshold

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread java-checks/src/main/java/org/sonar/java/checks/HardcodedMathConstantCheck.java Outdated
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Ruling needs updating. A fix PR has been created: #5876

Please review and merge it into your branch.

Octal and binary notation do not exist for Java floating-point literals,
so the octal/binary guards in normalize() were dead code that could cause
false negatives for leading-zero decimal float literals like 03.14159.
Keep only the hex float literal guard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Ruling needs updating. A fix PR has been created: #5876

Please review and merge it into your branch.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@gitar-bot

gitar-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 3 resolved / 3 findings

Implements new rule S9133 to detect hard-coded floating-point approximations of mathematical constants, addressing looseness in tolerance, missing normalize() edge case tests, and incorrect octal/binary skip checks. No issues found.

✅ 3 resolved
Edge Case: Loose tolerance may flag legitimate 3-digit domain values

📄 java-checks/src/main/java/org/sonar/java/checks/HardcodedMathConstantCheck.java:28-29 📄 java-checks/src/main/java/org/sonar/java/checks/HardcodedMathConstantCheck.java:79-85
With RELATIVE_TOLERANCE=0.002 and only MIN_SIGNIFICANT_DIGITS=3, a literal that matches a constant only in its first ~3 digits (e.g. 2.72 for E, or 0.693 which is a common domain value) is flagged even though the author clearly did not intend the constant's full precision. This can create false positives on genuine domain literals. Consider requiring the literal to match the constant across all of its own significant digits (i.e., the error should be on the order of the literal's own rounding) rather than a fixed relative window, to reduce noise while still catching approximations like 3.14159.

Quality: No tests for normalize() edge cases (underscores, D suffix, leading dot)

📄 java-checks/src/main/java/org/sonar/java/checks/HardcodedMathConstantCheck.java:88-102 📄 java-checks-test-sources/default/src/main/java/checks/HardcodedMathConstantCheckSample.java:1-15
normalize() handles digit separators ("3.14_159"), upper/lower 'd'/'D'/'F' suffixes, and the sample covers 'f' and 'e'/hex, but there is no test exercising an underscore-separated literal, a 'D'/'d' suffixed double, or a leading-dot literal (e.g. ".314159e1"). Add sample lines such as double a = 3.14_159; and double b = 3.14159d; to lock in this normalization behavior against regressions.

Edge Case: Octal/binary skip check wrongly ignores leading-zero float literals

📄 java-checks/src/main/java/org/sonar/java/checks/HardcodedMathConstantCheck.java:99-104
This branch only runs for DOUBLE_LITERAL/FLOAT_LITERAL tokens, but octal and binary notation do not exist for Java floating-point literals — leading zeros are legal in decimal float literals. So a literal like 03.14159 (a valid double equal to 3.14159) matches charAt(0)=='0' && Character.isDigit(charAt(1)) and is silently skipped, producing a false negative. The 0b/0B checks are dead code for the same reason. Remove the octal/binary conditions and keep only the hex guard.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next

sonarqube-next Bot commented Aug 4, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants