SONARJAVA-6786: S9346 - Integer values should not be cast to long for use as timestamps - #6027
SONARJAVA-6786: S9346 - Integer values should not be cast to long for use as timestamps#6027romainbrenguier wants to merge 1 commit into
Conversation
Improve the rule description with clearer explanations of the Year 2038 problem, code examples, and potential impact. Update JSON metadata to use "Main" scope and reformat for consistency. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
| <pre data-diff-id="1" data-diff-type="noncompliant"> | ||
| int timestamp = 1234567890; | ||
| Date date = new Date(timestamp); // Noncompliant — int implicitly widened | ||
| Date date2 = new Date((long) timestamp); // Noncompliant — cast doesn't fix overflow | ||
| long epochMillis = (long) timestamp; // Noncompliant | ||
| Date date = new Date(epochMillis); | ||
| </pre> | ||
| <h3>Compliant solution</h3> | ||
| <h4>Compliant solution</h4> | ||
| <pre data-diff-id="1" data-diff-type="compliant"> | ||
| long timestamp = 1234567890L; | ||
| Date date = new Date(timestamp); | ||
| Date date2 = new Date(timestamp); | ||
| long epochMillis = timestamp; | ||
| Date date = new Date(epochMillis); | ||
| </pre> |
There was a problem hiding this comment.
⚠️ Bug: S9346 noncompliant example shows a case the rule never reports
The new noncompliant snippet marks long epochMillis = (long) timestamp; as the issue line, but IntegerToLongTimestampCastCheck only reports on arguments of Date/Timestamp constructors and Instant.ofEpochSecond/ofEpochMilli/Calendar.setTimeInMillis (checkArgument is reached only from onMethodInvocationFound/onConstructorFound). A standalone cast in a variable initializer is explicitly asserted compliant in the test sample (compliantNonTimestampCast: long result = (long) intVar;), and new Date(epochMillis) passes a long, so this example raises no issue at all — the previous example (new Date(timestamp) / new Date((long) timestamp)) did. Restore examples where the int-typed value is passed directly to the timestamp API, which is where the rule actually reports.
Use examples where the narrow-typed value reaches a timestamp API, matching the patterns the check reports.:
<pre data-diff-id="1" data-diff-type="noncompliant">
int timestamp = 1234567890;
Date date = new Date(timestamp); // Noncompliant, int implicitly widened
Date date2 = new Date((long) timestamp); // Noncompliant, the cast does not fix the overflow
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="compliant">
long timestamp = 1234567890L;
Date date = new Date(timestamp);
Date date2 = new Date(timestamp);
</pre>
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
There was a problem hiding this comment.
Confirmed by running the analyzer locally against the exact documentation example. I temporarily added this method to IntegerToLongTimestampCastCheckSample.java:
void compliantPrDocumentationExample() {
int timestamp = 1234567890;
long epochMillis = (long) timestamp;
new Date(epochMillis);
}I left it without a Noncompliant marker, so CheckVerifier.verifyIssues() would fail if S9346 reported anything on it. I then ran:
mvn -pl java-checks -Dtest=IntegerToLongTimestampCastCheckTest test
Result: Tests run: 1, Failures: 0, Errors: 0 / BUILD SUCCESS, confirming that the analyzer does not raise an issue for the PR example. I removed the temporary test addition afterward.
There was a problem hiding this comment.
Thanks for the thorough verification — that confirms the noncompliant example in S9346.html doesn't actually trigger the rule.
| <p>This is an issue when a smaller integer type value is widened to a larger integer type and then used as an absolute timestamp, such as milliseconds | ||
| or seconds since the Unix epoch (January 1, 1970).</p> |
There was a problem hiding this comment.
💡 Quality: Rule description omits the narrowing-cast pattern the check reports
The intro now scopes the rule to "a smaller integer type value is widened to a larger integer type", and "How to fix it" only says to change the variable type from int to long. The check also reports narrowing casts of already-correct long values (new Date((int) longVar) is asserted noncompliant in the test sample), for which the documented fix (changing the declared type) does not apply — a user hitting that issue gets no applicable guidance. Mention removing the narrowing cast as a second fix case.
Document the narrowing-cast case in the "How to fix it" section.:
<p>Change the variable type from <code>int</code> to <code>long</code> to properly represent the timestamp. This ensures the value can hold the full
range of possible timestamp values without overflow. When the value is already a <code>long</code>, remove any narrowing cast to <code>int</code>,
<code>short</code>, <code>byte</code> or <code>char</code> that truncates it before it is used as a timestamp.</p>
- Apply fix
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎
Code Review
|
| Auto-apply | Compact | Unblock |
|
|
|
Was this helpful? React with 👍 / 👎 | Gitar
nathsou
left a comment
There was a problem hiding this comment.
Please review Gitar's findings as I they seem valid, apart from that, it looks good to me.
|
The update where made on the rspec side: https://github.com/SonarSource/rspec/pull/7997 |





Summary
Test plan
🤖 Generated with Claude Code