Skip to content

SONARJAVA-6789: Implement S9353: disallow unescaped '.' as a regex literal - #5955

Merged
nathsou merged 5 commits into
masterfrom
new-rule/S9353
Aug 19, 2026
Merged

SONARJAVA-6789: Implement S9353: disallow unescaped '.' as a regex literal#5955
nathsou merged 5 commits into
masterfrom
new-rule/S9353

Conversation

@nathsou

@nathsou nathsou commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Implement S9353 as a native SonarJava check that flags a constant "." regex argument on String.split / matches / replaceAll / replaceFirst and Pattern.compile / Pattern.matches.
  • Skip Pattern.compile when the flags include Pattern.LITERAL.
  • Add focused CheckVerifier tests, including .withoutSemantic(), plus generated rule metadata and the Sonar way profile entry.

Links

AI disclosure

  • LLM model used for implementation: cursor-grok-4.6-high

@nathsou nathsou self-assigned this Aug 19, 2026
@hashicorp-vault-sonar-prod

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

Copy link
Copy Markdown
Contributor

SONARJAVA-6789

gitar-bot[bot]

This comment was marked as resolved.

@github-actions

Copy link
Copy Markdown
Contributor

Ruling Diff Summary

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

S9353 (java) on regex-examples - 0 issues removed, 2 issues added - new ruling file

Added src/main/java/org/regex/examples/RegexDatabase2.java (line 457)

       452 |     // https://github.com/googleapis/google-api-java-client-services/blob/81e2a6698f5f960ae493c0acdefe830514531bf5/clients/google-api-services-accessapproval/v1/1.31.0/com/google/api/services/accessapproval/v1/AccessApproval.java#L2442
       453 |     Pattern.compile("^projects/[^/]+/accessApprovalSettings$"),
       454 |     // https://github.com/googleapis/google-api-java-client-services/blob/81e2a6698f5f960ae493c0acdefe830514531bf5/clients/google-api-services-accessapproval/v1/1.31.0/com/google/api/services/accessapproval/v1/AccessApproval.java#L2920
       455 |     Pattern.compile("^projects/[^/]+/approvalRequests/[^/]+$"),
       456 |     // https://github.com/atp-mipt/jsyntrax/blob/4ca79decf441cba9ab67928935c57efdd33a348c/jsyntrax/src/main/java/org/atpfivt/jsyntrax/styles/NodeTokenStyle.java#L11
>>>    457 |     Pattern.compile("."),
       458 |     // https://github.com/atp-mipt/jsyntrax/blob/4ca79decf441cba9ab67928935c57efdd33a348c/jsyntrax/src/main/java/org/atpfivt/jsyntrax/styles/NodeHexStyle.java#L11
       459 |     Pattern.compile("^\\w"),
       460 |     // https://github.com/atp-mipt/jsyntrax/blob/4ca79decf441cba9ab67928935c57efdd33a348c/jsyntrax/src/main/java/org/atpfivt/jsyntrax/styles/NodeBoxStyle.java#L10
       461 |     Pattern.compile("^/"),
       462 |     // https://github.com/saiprakash774/Userregistration/blob/33ca8b01235c6da18ebe0380b950118bd1789eea/UserRegistration.java#L15

Added src/main/java/org/regex/examples/RegexDatabase8.java (line 1129)

      1124 |     // https://github.com/LmaaMiracle/StudentAssistantBot/blob/ad0fb69c2e5f3bec786dbf949879448b21c95be9/documentation/4_Software_Construction/4.2_Construction_of_Program%20Modules/4.2.3%20%D0%9E%D1%81%D0%BE%D0%B1%D0%BB%D0%B8%D0%B2%D0%BE%D1%81%D1%82%D1%96%20%D1%81%D1%82%D0%B2%D0%BE%D1%80%D0%B5%D0%BD%D0%BD%D1%8F%20%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BD%D0%B8%D1%85%20%D0%BA%D0%BB%D0%B0%D1%81%D1%96%D0%B2/BotState.java#L374
      1125 |     Pattern.compile("([01][0-9]|2[0-3]):[0-5][0-9]"),
      1126 |     // https://github.com/dearcode2018/file/blob/857c774411c3689f2613d2c8d945b8b78e3214d2/poi/src/main/java/com/hua/util/POIUtil.java#L512
      1127 |     Pattern.compile("\\(.+\\)"),
      1128 |     // https://github.com/raise-isayan/YaguraExtender/blob/04d52bd802c91ef4ffb957898badb03248fa0724/src/main/java/extend/util/external/TransUtil.java#L166
>>>   1129 |     Pattern.compile(".", Pattern.DOTALL),
      1130 |     // https://github.com/raise-isayan/YaguraExtender/blob/04d52bd802c91ef4ffb957898badb03248fa0724/src/main/java/extend/util/external/TransUtil.java#L168
      1131 |     Pattern.compile("[^A-Za-z0-9!\"$'()*,/:<>@\\[\\\\\\]^`{|}~]"),
      1132 |     // https://github.com/raise-isayan/YaguraExtender/blob/04d52bd802c91ef4ffb957898badb03248fa0724/src/main/java/extend/util/external/TransUtil.java#L169
      1133 |     Pattern.compile("[^A-Za-z0-9\"<>\\[\\\\\\]^`{|}]"),
      1134 |     // https://github.com/raise-isayan/YaguraExtender/blob/04d52bd802c91ef4ffb957898badb03248fa0724/src/main/java/extend/util/external/TransUtil.java#L170

@gitar-bot
gitar-bot Bot dismissed their stale review August 19, 2026 10:11

✅ All code review findings resolved.

Configure merge blocking

Use a shared method-name constant to satisfy S1192 without changing rule behavior.
Keep NOSONAR as the only documented suppression for intentional "." regexes.
@sonarqube-next

Copy link
Copy Markdown
Contributor

@nathsou
nathsou merged commit cdfc77c into master Aug 19, 2026
16 checks passed
@nathsou
nathsou deleted the new-rule/S9353 branch August 19, 2026 14:24
@gitar-bot

gitar-bot Bot commented Aug 19, 2026

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

Implements S9353 to flag unescaped '.' regex arguments across String and Pattern methods, skipping compile calls with Pattern.LITERAL. No issues found.

✅ 2 resolved
Bug: withoutSemantic test asserts issues that can never fire

📄 java-checks/src/test/java/org/sonar/java/checks/BareDotRegexpCheckTest.java:34-41 📄 java-checks/src/main/java/org/sonar/java/checks/BareDotRegexpCheck.java:33-47
test_without_semantic runs the same sample file with .withoutSemantic() and calls verifyIssues(). Because this check is built on AbstractMethodDetection/MethodMatchers keyed on owner types (java.lang.String, java.util.regex.Pattern), method matching requires type resolution — with semantics disabled every match fails and zero issues are reported, so verifyIssues() fails against the file's // Noncompliant expectations. Change the no-semantic test to assert absence of issues via verifyNoIssues().

Quality: quickfix metadata says "targeted" but no quick fix implemented

📄 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9353.json:16 📄 java-checks/src/main/java/org/sonar/java/checks/BareDotRegexpCheck.java:70-76
S9353.json declares "quickfix": "targeted", yet BareDotRegexpCheck only calls reportIssue(...) and implements no quick fix. Other rules without a quick fix use "infeasible". This isn't enforced by a test, but escaping a bare dot is a straightforward, mechanical replacement — either implement the quick fix to justify "targeted", or set the value to "infeasible" to avoid misrepresenting current capabilities.

Implementation Status 🟡 0 / 1 issues implemented
SONARJAVA-6789 — 0 / 1 objectives

The PR does not contain any code changes implementing rule S9353.

  • ⬜ Implement rule S9353 to disallow unescaped '.' as a regex literal in regex methods like split, replaceAll, replaceFirst, matches, and Pattern.compile
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

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