Skip to content

SONARJAVA-7070: Implemented rule S9413 Redundant "String.format" should be removed when native formatting is available - #6246

Merged
romainbrenguier merged 9 commits into
masterfrom
romain/new-rule-s9413-sonarjava-7070
Oct 1, 2026
Merged

romainbrenguier merged 9 commits into
masterfrom
romain/new-rule-s9413-sonarjava-7070

Conversation

@romainbrenguier

@romainbrenguier romainbrenguier commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

SONARJAVA-7070

Summary

  • Add RedundantStringFormatCheck (S9413). It reports String.format(...) when its result is passed directly as the message argument of an API that already formats:
    • SLF4J / Log4j 2 logging methods → use the logger's {} placeholders
    • PrintStream / PrintWriter print / println → use printf
  • "Message argument" means the first declared String parameter of the target. So LOG.info("v: {}", String.format("%.2f", x)) is not reported.
  • Logging calls are only reported when the format is a literal that uses nothing but %s, %d and %%. Width/precision/flags, other conversions, non-literal formats, Locale overloads and java.util.Formattable arguments are ignored, because {} placeholders can't reproduce them (%s calls formatTo on Formattable values). Any format is reported for print/println, because printf accepts the same syntax.
  • Quick fix for the printing case: print(String.format(...)) → printf(...), and println(String.format("...", ...)) → printf("...%n", ...) when the format is a string literal. The Locale and argument order are kept.
  • Cases left to other rules or dropped: string concatenation instead of String.format in exception constructors is covered by S9397. StringBuilder/StringBuffer append is not reported.
  • Add rule metadata (HTML, JSON) and include the rule in the Sonar way profile.

Testing notes

  • JDK targets and logging targets have separate samples (RedundantStringFormatCheckSample, RedundantStringFormatCheckLoggingSample). Both run with and without semantic. Without semantic, the logging sample reports no issues because the method symbols are unknown.

Agent workflow

PR created using uv run new_rule_implementation.py S9413 -j SONARJAVA-7070 -a claude -g AGENTS.md .claude/skills/new-rule/SKILL.md
Tool link: https://github.com/SonarSource/languages-experimental-tooling/tree/romain/my-tickets/personal/romain-brenguier

PR created using uv run create_with_claude.py /tmp/action_plan_romain/new-rule-s9413-sonarjava-7070.txt

Iterated on the PR with uv run ci_loop.py for 1 iterations.
✔️ The PR is now ready for review.

PR updated using uv run update_with_claude.py --prompt "Implement the action plan described in the document Drop from the current implementation of the rule the case about using string concatenation instead of String.format. That case is already handled by rule S9397.." -a "Drop from the current implementation of the rule the case about using string concatenation instead of String.format. That case is already handled by rule S9397." -g "claude"

PR updated using uv run update_with_claude.py --prompt "Implement the action plan described in the document Modify the rule so that it no longer applies to the StringBuilder.append case. Update the PR description and the html description accordingly. Then address the comments by nathsou on the PR..."

🤖 Generated with Claude Code

PR updated using uv run update_with_claude.py --prompt "Implement the action plan described in the document Modify the rule so that it no longer applies to the StringBuilder.append case. Update the PR description and the html description accordingly. Then address the comments by nathsou on the PR.." -a "Modify the rule so that it no longer applies to the StringBuilder.append case. Update the PR description and the html description accordingly. Then address the comments by nathsou on the PR." -g "claude"

…ld be removed when native formatting is available

Reports String.format calls passed directly as the message argument of APIs
with native formatting: SLF4J/Log4j 2 loggers, PrintStream/PrintWriter
print/println, StringBuilder/StringBuffer append, and Throwable constructors.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

SONARJAVA-7070

Comment thread sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9413.html Outdated
@datadog-sonarsource

This comment has been minimized.

🤖 Generated with GitHub Actions
@github-actions

Copy link
Copy Markdown
Contributor

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

Please review and merge it into your branch.

romainbrenguier and others added 2 commits September 28, 2026 11:19
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Ruling Diff Summary

Detected changes in 2 rule files: 0 issues removed, 12 issues added.

S9413 (java) on eclipse-jetty - 0 issues removed, 6 issues added - new ruling file

Added jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java (line 1974)

(source file not found at this revision: jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java)

Added jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java (line 368)

(source file not found at this revision: jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java)

Added jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartParser.java (line 714)

(source file not found at this revision: jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartParser.java)

Added jetty-server/src/main/java/org/eclipse/jetty/server/Server.java (line 420)

(source file not found at this revision: jetty-server/src/main/java/org/eclipse/jetty/server/Server.java)

Added jetty-server/src/main/java/org/eclipse/jetty/server/Server.java (line 440)

(source file not found at this revision: jetty-server/src/main/java/org/eclipse/jetty/server/Server.java)

Added jetty-server/src/main/java/org/eclipse/jetty/server/Server.java (line 480)

(source file not found at this revision: jetty-server/src/main/java/org/eclipse/jetty/server/Server.java)
S9413 (java) on eclipse-jetty-similar-to-main - 0 issues removed, 6 issues added - new ruling file

Added jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java (line 1974)

(source file not found at this revision: jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java)

Added jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java (line 368)

(source file not found at this revision: jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java)

Added jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartParser.java (line 714)

(source file not found at this revision: jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartParser.java)

Added jetty-server/src/main/java/org/eclipse/jetty/server/Server.java (line 420)

(source file not found at this revision: jetty-server/src/main/java/org/eclipse/jetty/server/Server.java)

Added jetty-server/src/main/java/org/eclipse/jetty/server/Server.java (line 440)

(source file not found at this revision: jetty-server/src/main/java/org/eclipse/jetty/server/Server.java)

Added jetty-server/src/main/java/org/eclipse/jetty/server/Server.java (line 480)

(source file not found at this revision: jetty-server/src/main/java/org/eclipse/jetty/server/Server.java)

🤖 Generated with GitHub Actions
@github-actions

Copy link
Copy Markdown
Contributor

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

Please review and merge it into your branch.

@romainbrenguier
romainbrenguier marked this pull request as ready for review September 28, 2026 09:58
String concatenation instead of String.format is already covered by S9397.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

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

Please review and merge it into your branch.

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

Copy link
Copy Markdown
Contributor

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

Please review and merge it into your branch.

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

@nathsou nathsou 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.

Approved, with the inline suggestions below.

Comment thread java-checks/src/main/java/org/sonar/java/checks/RedundantStringFormatCheck.java Outdated
… review

- Stop reporting String.format passed to StringBuilder/StringBuffer.append.
- Skip logging cases when a format argument implements java.util.Formattable,
  since %s calls formatTo while "{}" placeholders call toString.
- Add a quick fix turning print/println(String.format(...)) into printf(...),
  appending %n for println when the format is a string literal.
- Remove stale ruling expectations for dropped cases.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gitar-bot

gitar-bot Bot commented Sep 30, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 2 closed / 2 findings

🟡 Medium risk · Adds a new Java analysis rule with reporting and output-rewriting quick fixes

Implements rule S9413 to detect and flag redundant String.format() calls when native formatting is available for SLF4J/Log4j 2 logging methods and PrintStream/PrintWriter APIs, with quick fixes for the printing case. Fixed invalid Java code examples in the S9413 HTML description and removed stale ruling expectations.

✅ 2 closed
✅ Quality: StringBuilder code examples in S9413.html are invalid Java

📄 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9413.html:139-141 📄 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9413.html:153-155
In the "How to fix it in StringBuilder" section, the escape backslashes on the JSON quotes were lost, so the examples read sb.append(String.format(""name":"%s",", name)); and sb.append(""name":"").append(name).append("",");. Neither the noncompliant nor the compliant block compiles, which makes the example hard to follow. The test sample (""name":"%s",") shows the intended code. Put the " escapes back in both blocks, or switch to a JSON-free example like "User: %s".

✅ Quality: Stale S9413 ruling expectations left in eclipse-jetty-similar-to-main

📄 its/ruling/src/test/resources/expected/eclipse-jetty-similar-to-main/java-S9413.json:2-4 📄 its/ruling/src/test/resources/expected/eclipse-jetty-similar-to-main/java-S9413.json:11-13 📄 its/ruling/src/test/resources/expected/eclipse-jetty/java-S9413.json:1-15 📄 java-checks/src/main/java/org/sonar/java/checks/RedundantStringFormatCheck.java:89-91
This commit removes the Throwable constructor case, and the bot's ruling update (33395fa) removed HttpGenerator.java:613 and HttpOutput.java:1345 from eclipse-jetty/java-S9413.json. Those same two entries, at the same line numbers, are still in eclipse-jetty-similar-to-main/java-S9413.json. That file was generated in 5741a3f, before the exception case was dropped, and nothing has updated it since. JavaRulingTest analyzes eclipse-jetty-similar-to-main as the PR build and checks its results against this expected file. The check can no longer report these two lines, so the incremental ruling IT will fail. The fix is to delete those two entries, or regenerate the file.

Review coverage

🧪 Functional validation 1 of 1 objectives covered

📋 Rules No rules evaluated

Cross-repo coverage 5 repositories selected

🤖 Auto-approval Not enabled · Set up

Implementation Status ✅ 1 of 1 objectives covered
✅ SONARJAVA-7070 - 1 of 1 objectives covered

This PR implements rule S9413 to remove redundant String.format when native formatting is available.

✅ 1 covered here
  • ✅ Implement rule S9413 to remove redundant String.format when native formatting is available
Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Counting what did not apply, without listing it.

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

Copy link
Copy Markdown
Contributor

@romainbrenguier
romainbrenguier merged commit 784773c into master Oct 1, 2026
19 checks passed
@romainbrenguier
romainbrenguier deleted the romain/new-rule-s9413-sonarjava-7070 branch October 1, 2026 08:57
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