SONARJAVA-6780: Implement S9354: Comparable.compareTo() and Comparator.compare() should not use subtraction on numerical fields - #5959
SONARJAVA-6780: Implement S9354: Comparable.compareTo() and Comparator.compare() should not use subtraction on numerical fields#5959nathsou wants to merge 9 commits into
Conversation
…r.compare() should not use subtraction on numerical fields
| "ruleSpecification": "RSPEC-9354", | ||
| "sqKey": "S9354", | ||
| "scope": "All", | ||
| "quickfix": "targeted", |
There was a problem hiding this comment.
💡 Quality: S9354.json declares quickfix "targeted" but no quick fix is implemented
S9354.json sets "quickfix": "targeted", yet IntegerSubtractionInComparisonCheck implements no quick fix (only reportIssue on the operator token). Other checks without an implemented quick fix declare "infeasible" or "covered" (e.g. S9351.json uses "infeasible"). While no automated test currently enforces this, the declared value is misleading and inconsistent with repo conventions; either implement the targeted quick fix (replace the subtraction with Integer.compare/Long.compare) or change the metadata to the accurate value.
Was this helpful? React with 👍 / 👎
|
❌ Ruling needs updating. A fix PR has been created: #5961 Please review and merge it into your branch. |
Ruling Diff SummaryDetected changes in 2 rule files: 0 issues removed, 16 issues added. S9354 (
|
|
❌ Ruling needs updating. A fix PR has been created: #5963 Please review and merge it into your branch. |
Ruling QA failed because java-S9354.json still expected issues from the first visitor that flagged every minus in compareTo. After reporting only when subtraction is the comparison result, AbstractPathSpec's intermediate diff and XmlConfiguration's index arithmetic are compliant.
SonarQube Code Analysis failed on 12.7% duplication with S9148 and 89.6% coverage on new code. Extract the shared Comparable/Comparator dispatch and add a block-lambda case so S9354 is no longer a near-copy of S9148.
…k list count GeneratedCheckListTest.count failed because every *Check.java is expected to be a registered rule. The new shared comparison-method base is abstract and has no @rule, matching the existing AbstractRegexCheck blacklist.
romainbrenguier
left a comment
There was a problem hiding this comment.
I don't think adding an abstract check class is a good idea.
| "quickfix": "targeted", | ||
| "code": { | ||
| "impacts": { | ||
| "RELIABILITY": "HIGH" |
There was a problem hiding this comment.
This doesn't seem coherent with the "defaultSeverity". I think it should be "MEDIUM" here. (To be fixed on the rspec PR).
There was a problem hiding this comment.
Fixed. defaultSeverity Major maps to a MEDIUM impact (same as S9350); HIGH is the Critical mapping used by S9148.
RSPEC: https://github.com/SonarSource/rspec/pull/7915 (37ad141ec9)
Analyzer metadata updated to match in 66c7c48b2d.
| "AbstractRedosCheck.java", | ||
| "AbstractRegexCheck.java"); | ||
| "AbstractRegexCheck.java", | ||
| "AbstractComparisonMethodCheck.java"); |
There was a problem hiding this comment.
Why is it blacklisted? I don't understand what this test is.
There was a problem hiding this comment.
count() asserts that every on-disk *Check.java is a registered rule in GeneratedCheckList. Abstract bases without @Rule have to be excluded (same list as AbstractRegexCheck).
That blacklist entry only existed because of AbstractComparisonMethodCheck. The abstract class is gone in 66c7c48b2d, so the entry is gone too.
| /** | ||
| * Shared entry point for checks that inspect {@code Comparable.compareTo} and {@code Comparator.compare}. | ||
| */ | ||
| abstract class AbstractComparisonMethodCheck extends IssuableSubscriptionVisitor { |
There was a problem hiding this comment.
I would stay away from creating abstract classes for checks. That creates coupling between rules, which we always want to avoid. If we need to avoid duplication, utility methods may be a solution.
There was a problem hiding this comment.
Agreed, sharing an abstract check coupled S9148 and S9354.
66c7c48b2d deletes AbstractComparisonMethodCheck. Each rule is a standalone IssuableSubscriptionVisitor again, and they only share ComparisonMethodUtils for the compareTo / Comparator.compare matchers.
S9148 and S9354 now share only ComparisonMethodUtils instead of an abstract check class. GeneratedCheckListTest no longer needs a blacklist entry, and RELIABILITY is MEDIUM to match Major severity.
The quality gate failed on 6.3% duplicated new code (limit 3%) because S9148 and S9354 still shared the same visitNode shape after dropping the abstract check class. ComparisonMethodUtils now owns that dispatch.
Code Review 👍 Approved with suggestions 1 resolved / 2 findingsImplements the S9354 check to flag integer and long subtraction in comparison methods and lambdas, restricting reports to direct comparison results. Ensure the S9354.json quickfix metadata aligns with the lack of an implemented quick fix. 💡 Quality: S9354.json declares quickfix "targeted" but no quick fix is implemented📄 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9354.json:16 📄 java-checks/src/main/java/org/sonar/java/checks/IntegerSubtractionInComparisonCheck.java:82-88 S9354.json sets ✅ 1 resolved✅ Bug: Flags any int/long subtraction in comparison body, not just the result
🤖 Prompt for agentsImplementation Status ✅ 1 / 1 issues implemented✅ SONARJAVA-6780 — 1 / 1 objectivesThe PR successfully implements rule S9354 to detect and report numerical field subtraction inside Comparable.compareTo() and Comparator.compare() methods and lambdas. ✅ 1 complete
OptionsAuto-apply is off → Gitar will not commit updates to this branch. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar |
|




Summary
int/longsubtraction insideComparable.compareTo(),Comparator.compare(), and Comparator lambdas.-operator, for exampleSubtracting numeric values in compareTo can overflow; use Long.compare instead.intdifference cannot overflow.Links
AI disclosure