Skip to content

SONARJAVA-6876 S2479 Reduce noise by suppressing on strings that are most likely generated - #6061

Merged
lijun-chen-sonarsource merged 5 commits into
masterfrom
lc/improve-S2479
Sep 1, 2026
Merged

SONARJAVA-6876 S2479 Reduce noise by suppressing on strings that are most likely generated#6061
lijun-chen-sonarsource merged 5 commits into
masterfrom
lc/improve-S2479

Conversation

@lijun-chen-sonarsource

@lijun-chen-sonarsource lijun-chen-sonarsource commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Part of AT-82


Summary by Gitar

  • New helper:
    • Added GeneratedStringLiteralRecognizer to suppress string literals likely generated in Kotlin annotations
  • Check updates:
    • Updated ControlCharacterInLiteralCheck to ignore recognized generated string literals

This will update automatically on new commits.

@hashicorp-vault-sonar-prod hashicorp-vault-sonar-prod Bot changed the title S2479 Reduce noise by suppressing on strings that are most likely generated SONARJAVA-6876 S2479 Reduce noise by suppressing on strings that are most likely generated Aug 28, 2026
@hashicorp-vault-sonar-prod

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

Copy link
Copy Markdown
Contributor

SONARJAVA-6876

@gitar-bot

gitar-bot Bot commented Aug 31, 2026

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

Adds GeneratedStringLiteralRecognizer to reduce noise in ControlCharacterInLiteralCheck by suppressing string literals likely generated in Kotlin annotations. The helper now checks for generated strings before the cheaper regex validation, and the semantic analysis path is covered by existing tests. No issues found.

✅ 3 resolved
Performance: isGenerated runs for every literal before the cheap regex check

📄 java-checks/src/main/java/org/sonar/java/checks/ControlCharacterInLiteralCheck.java:68-82 📄 java-checks/src/main/java/org/sonar/java/checks/helpers/GeneratedStringLiteralRecognizer.java:52-66
isGenerated is invoked as the first statement of visitNode, so for every string/char literal/text block in every analysed file it walks the parent chain up to the compilation-unit root (the while loop only stops on an ARGUMENTS parent, which the vast majority of literals never have), and in the unresolved-type case it additionally runs concatenate plus a full import scan up to three times. The suppression is only needed for the tiny fraction of literals that actually contain a control character, so moving the call behind matcher.find() yields identical behaviour with strictly less work on the hot path of a rule that subscribes to all literals.

Quality: No withoutSemantic() test; shadowing case only covers semantic path

📄 java-checks/src/test/java/org/sonar/java/checks/helpers/GeneratedStringLiteralRecognizerTest.java:32-46 📄 java-checks-test-sources/default/src/main/java/checks/helpers/GeneratedStringLiteralRecognizerSample.java:3 📄 java-checks-test-sources/default/src/main/java/checks/helpers/GeneratedStringLiteralRecognizerSample.java:32-41
The new test class only runs with the full classpath and with withClassPath(List.of()), not with the repo-mandated withoutSemantic(). InternalCheckVerifier.scanFiles skips enableSemanticWithProjectClasspath when withoutSemantic is set, so in that mode even the source-declared nested @interface Metadata has an unknown symbolType; isAnnotationType then falls back to simple-name matching and finds import kotlin.Metadata in the same file, so ShadowedMetadataSample.Annotated (line 38, marked // Compliant) would be classified as generated. The shadowing scenario the sample claims to cover is therefore only validated on the resolved-type path. Add the withoutSemantic() test and put the shadowing case in a file that does not import kotlin.Metadata so it is meaningful in both modes; also add a text-block case, since isGenerated explicitly accepts Tree.Kind.TEXT_BLOCK but no text block appears in the sample.

Bug: Unknown-type fallback now needs bindings; breaks without semantics

📄 java-checks/src/main/java/org/sonar/java/checks/helpers/GeneratedStringLiteralRecognizer.java:75-80 📄 java-checks/src/main/java/org/sonar/java/checks/ControlCharacterInLiteralCheck.java:81-83 📄 java-checks/src/main/java/org/sonar/java/checks/helpers/GeneratedStringLiteralRecognizer.java:26-35 📄 java-checks/src/test/java/org/sonar/java/checks/helpers/GeneratedStringLiteralRecognizerTest.java:79-93
The fallback for unresolved annotations changed from a purely syntactic check (ExpressionsHelper.concatenate(annotation.annotationType()) plus an explicit-import check) to annotation.symbolType().name(). When no ECJ bindings exist at all (semantic disabled — AbstractTypedTree.symbolType() returns Type.UNKNOWN and Symbols.UnknownType.name() is "!Unknown!"), name() can never equal Metadata/SourceDebugExtension/DebugMetadata, so suppression silently stops working; the old syntactic path still worked there. Concretely, checks/ControlCharacterInLiteralCheck.java:5 (@Metadata(d1 = {"U+200B …"}) // Compliant, generated string) is scanned by ControlCharacterInLiteralCheckTest.test_without_semantic(), which will now get an unexpected issue on that line. Keep a syntax-based fallback (annotation type tree name) for the unresolved case instead of relying on symbolType().name().

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

Copy link
Copy Markdown
Contributor

@asya-vorobeva asya-vorobeva 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.

💯

@lijun-chen-sonarsource
lijun-chen-sonarsource merged commit e2872b7 into master Sep 1, 2026
26 checks passed
@lijun-chen-sonarsource
lijun-chen-sonarsource deleted the lc/improve-S2479 branch September 1, 2026 08:58
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