Skip to content

SONARJAVA-6944: Implement rule S9387 TestNG Javadoc tags should be converted to annotations - #6124

Open
romainbrenguier wants to merge 7 commits into
masterfrom
romain/new-rule-s9387-sonarjava-6944
Open

romainbrenguier wants to merge 7 commits into
masterfrom
romain/new-rule-s9387-sonarjava-6944

Conversation

@romainbrenguier

Copy link
Copy Markdown
Contributor

Summary

  • Implement new rule S9387 that detects TestNG-specific Javadoc tags (@test, @beforeMethod, @afterMethod, @beforeClass, @afterClass, @dataProvider, etc.) used as configuration markers instead of proper TestNG annotations
  • Case-insensitive matching for all 15 TestNG tags with secondary locations when multiple tags appear on a single method
  • Includes test sample with compliant and noncompliant examples covering edge cases (case variants, mixed standard/TestNG tags, non-Javadoc comments)

Test plan

  • Unit tests pass (with and without semantic analysis)
  • CI build passes
  • Ruling tests updated if needed (auto-PR)

🤖 Generated with Claude Code

…nverted to annotations

Detect TestNG-specific Javadoc tags (@test, @beforeMethod, @afterMethod, etc.)
used as configuration markers instead of proper TestNG annotations (@test,
@BeforeMethod, @AfterMethod, etc.). Case-insensitive matching with support
for all 15 TestNG tags and secondary locations for multiple tags per method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

SONARJAVA-6944

Comment thread java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java Outdated
Comment thread java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java Outdated
Comment thread java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java Outdated
Comment thread java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java Outdated
romainbrenguier and others added 2 commits September 14, 2026 10:24
Addresses code review feedback:

1. Single-line Javadoc `/** @test */` is now detected by updating BLOCK_TAG_PATTERN to match tags following the `/**` opener
2. False positives from annotation examples in `<pre>` and `{@code}` blocks are eliminated by removing those regions before pattern matching
3. Issue and secondary locations now report precisely on the method name using `simpleName()` and avoid redundant operations
4. Type-only tags (`@beforeClass`, `@afterClass`, `@parameters`, `@listeners`) removed from method-level checks since they cannot be applied to methods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…icate test

@BeforeClass and @afterclass are method-level annotations in TestNG
(@target(METHOD)), not type-only. The previous commit incorrectly
removed them from the tag map.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9387.html Outdated
romainbrenguier and others added 4 commits September 14, 2026 10:52
- Revert manually added @beforeClass/@afterclass entries in S9387.html
  (auto-generated from RSPEC, should not be hand-edited)
- Move @beforeClass/@afterclass noncompliant test cases above the
  "Compliant cases" section for clarity
- Add secondary location assertion to multipleTestNGTags test case

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace \s with [\t ] in regex patterns to avoid super-linear
backtracking (SonarQube S8786). Use tree.simpleName() for secondary
locations to match the primary issue location scope.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…in S9387

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gitar-bot

gitar-bot Bot commented Sep 14, 2026

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

Implements rule S9387 to detect TestNG Javadoc tags (@test, @beforeMethod, @afterMethod, etc.) that should be converted to annotations. Addresses seven findings: single-line Javadoc detection, annotation examples in <pre>/{@code} blocks, issue and secondary location spans, class-level tag reachability, rule description editing, noncompliant sample placement, and secondary-location assertions in test samples.

✅ 7 resolved
Bug: Single-line Javadoc /* @test / is never detected

📄 java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java:36 📄 java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java:63-70 📄 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9387.html:19 📄 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9387.html:36-40 📄 java-checks-test-sources/default/src/main/java/checks/tests/TestNGJavadocTagsCheckSample.java:5-9
BLOCK_TAG_PATTERN anchors every match to ^ (MULTILINE), so a tag is only found when it starts a line, optionally after a leading *. For the single-line form /** @test */ the only ^ position is offset 0, where the next character is /, so the match fails and no issue is raised — yet that is exactly the form the rule description presents as noncompliant (Javadoc-style tags such as /** @test */, and the whole "How to fix it" list). Allow the tag to follow the /** opener, e.g. Pattern.compile("(?:^|/\*\*)\s*\*?\s*@(\w+)", Pattern.MULTILINE), and add a /** @test */ case to the sample file. (The same filter also ignores CommentKind.MARKDOWN, so /// @test doc comments are silently skipped.)

Edge Case: Annotation examples in <pre>/{@code} Javadoc blocks are flagged

📄 java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java:36 📄 java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java:76-90 📄 java-checks-test-sources/default/src/main/java/checks/tests/TestNGJavadocTagsCheckSample.java:97-107
Matching is case-insensitive, so a Javadoc that documents usage by embedding a code sample raises a false positive: in `/**

  • @test
  • public void t() {}

/the line @testsatisfies^\s**?\s*@(\w+)and is reported as a legacy TestNG tag, even though it is illustrating the correct annotation. Skip regions inside

/{@code ...}` (or require the tag line to contain nothing but the tag) before reporting.

Quality: Issue and secondary locations both span the whole method

📄 java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java:84-98
reportIssue(tree, ...) on a METHOD/CONSTRUCTOR tree highlights the entire declaration including the body, while every comparable check in this repo reports on ((MethodTree) tree).simpleName(); worse, each secondary location is built from the same tree, so "Also replace "@beforeMethod"..." points at the identical range as the primary message instead of at the second tag (matcher offsets relative to trivia.range().start() are available for that, see MarkdownJavadocSyntaxCheck). The if (secondaryLocations.isEmpty()) branch is also redundant since reportIssue accepts an empty list, and line 86 repeats the map lookup already held in annotation.

Edge Case: Class-level tags unreachable while @listeners is method-only advice

📄 java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java:53 📄 java-checks/src/main/java/org/sonar/java/checks/tests/TestNGJavadocTagsCheck.java:57-59 📄 java-checks-test-sources/default/src/main/java/checks/tests/TestNGJavadocTagsCheckSample.java:91-95
nodesToVisit() only registers METHOD and CONSTRUCTOR, but listeners (and parameters) map to TestNG annotations that are declared on a type — org.testng.annotations.Listeners is @Target(TYPE). As a result a class Javadoc carrying @listeners/@beforeClass is never inspected, and when the tag appears on a method the rule advises adding @Listeners there, which does not compile. Either add Tree.Kind.CLASS/INTERFACE/ENUM/RECORD to the visited kinds, or drop the type-only tags from the map.

Quality: Generated rule description S9387.html edited by hand

📄 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9387.html:39-40
This commit adds two <li> entries to S9387.html, but that folder's own README states the files are generated from RSPEC and "do not attempt to manually modify files here, nor submit Pull Request (PR) modifying description or rule metatada. Any PR will be systematically rejected." The next rule-api sync will drop the @beforeClass/@afterClass bullets, leaving the shipped rule description inconsistent with the implementation, which now raises on those two tags. Update RSPEC-9387 upstream and regenerate S9387.html/S9387.json rather than editing the resource in this repo.

...and 2 more resolved from earlier reviews

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

This PR implements the rule S9387 to detect TestNG Javadoc tags and suggest converting them to annotations.

✅ 1 covered here
  • ✅ Implement rule S9387 TestNG Javadoc tags should be converted to annotations
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 marked this pull request as ready for review September 14, 2026 14:40
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.

1 participant