Skip to content

SONARJAVA-6454 : Rule S8714 - implement quickfix#5663

Draft
rombirli wants to merge 27 commits into
masterfrom
rombirli/sonarjava-6406-create-rule-S8714
Draft

SONARJAVA-6454 : Rule S8714 - implement quickfix#5663
rombirli wants to merge 27 commits into
masterfrom
rombirli/sonarjava-6406-create-rule-S8714

Conversation

@rombirli
Copy link
Copy Markdown
Contributor

@rombirli rombirli commented Jun 8, 2026


Summary by Gitar

  • New implementation:
    • Added quickfix support for AssertThrowsInsteadOfTryCatchFailCheck for both JUnit and AssertJ.
    • Implemented TryCatchUtils helper to centralize catch block type extraction logic.
  • Refactoring:
    • Migrated getCaughtTypes logic from InterruptedExceptionCheck to the new shared TryCatchUtils helper.
  • Test updates:
    • Updated AssertThrowsInsteadOfTryCatchFailCheckSample to correctly categorize JUnit failure cases and add new test coverage.
    • Added TryCatchUtilsTest to verify catch block type resolution.
  • Quickfix features:
    • Introduced Replacements record to handle automated code transformations for JUnit assertThrows and AssertJ assertThatCode patterns.

This will update automatically on new commits.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 8, 2026

Agentic Analysis: Early Results

Agentic Analysis and Context Augmentation are available on your project. Here are some issues that could have been prevented. Follow the links to learn how to put them into action.

6 issue(s) found across 1 file(s):

Rule File Line Message
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/AssertThrowsInsteadOfTryCatchFailCheckSample.java 91 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/AssertThrowsInsteadOfTryCatchFailCheckSample.java 91 Move this trailing comment on the previous empty line.
java:S125 java-checks-test-sources/default/src/test/java/checks/tests/AssertThrowsInsteadOfTryCatchFailCheckSample.java 99 This block of commented-out lines of code should be removed.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/AssertThrowsInsteadOfTryCatchFailCheckSample.java 99 Move this trailing comment on the previous empty line.
java:S108 java-checks-test-sources/default/src/test/java/checks/tests/AssertThrowsInsteadOfTryCatchFailCheckSample.java 101 Remove this block of code, fill it in, or add a comment explaining why it is empty.
java:S139 java-checks-test-sources/default/src/test/java/checks/tests/AssertThrowsInsteadOfTryCatchFailCheckSample.java 120 Move this trailing comment on the previous empty line.

Analyzed by SonarQube Agentic Analysis in 2.9 s

@hashicorp-vault-sonar-prod
Copy link
Copy Markdown
Contributor

hashicorp-vault-sonar-prod Bot commented Jun 8, 2026

SONARJAVA-6406

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.

The contents of the PR changed. Let me send you the comments I had. I'll finish the review when the contents is stable.


public static List<Type> getCaughtTypes(CatchTree tree) {
VariableTree parameter = tree.parameter();
if (parameter.type().is(Tree.Kind.UNION_TYPE)) {
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.

Can we do ... instanceof UnionTypeTree unio.TypeTree and avoid cast below?

Comment thread java-checks/src/main/java/org/sonar/java/checks/helpers/TryCatchUtils.java Outdated
Comment thread java-checks/src/main/java/org/sonar/java/checks/helpers/TryCatchUtils.java Outdated
/* This utility class should not be instantiated */
}

public static List<Type> getCaughtTypes(CatchTree tree) {
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.

This method should have a test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. But the test is actually more complicated and contains more logic than the method itself (it tests more test code than prod code)

junitReplacement(failArguments, tryStatement, isTryBlock);
issueBuilder.withQuickFix(() ->
JavaQuickFix.newQuickFix(issueMessage).addTextEdit(
JavaTextEdit.replaceTree(tryStatement.tryKeyword(), replacements.replaceTryWith),
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.

I commented out code here and the unit tests still passed. Is this at all executed in tests?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes : currently unit testing quickfixes is very hard to setup because of improper logging, and those unit tests don't make much sense. They only assert that the list of edits matches the expected list of edits but not that the fixed version of the code matches the expected fixed code. Let me know if you find it strictly necessary to test this part, i can cover it (and make it fail if you comment it out).

@rombirli rombirli changed the title SONARJAVA-6406 : Rule S8714 - implement quickfix SONARJAVA-6454 : Rule S8714 - implement quickfix Jun 8, 2026
Comment thread java-checks/src/test/java/org/sonar/java/checks/helpers/TryCatchUtilsTest.java Outdated
@gitar-bot
Copy link
Copy Markdown

gitar-bot Bot commented Jun 8, 2026

Code Review ✅ Approved 5 resolved / 5 findings

Implements quickfix support for S8714 by introducing TryCatchUtils and handling JUnit/AssertJ transformations. Resolved issues include removing debug print statements, fixing wildcard imports, and preventing potential NPEs in catch block analysis.

✅ 5 resolved
Bug: Test comment typo '// NonCompliant' is not recognized by verifier

📄 java-checks-test-sources/default/src/test/java/checks/tests/AssertThrowsInsteadOfTryCatchFailCheckSample.java:12
In AssertThrowsInsteadOfTryCatchFailCheckSample.java:12 the expected-issue marker was changed from // Noncompliant to // NonCompliant. The CheckVerifier only recognizes the case-sensitive flag Noncompliant (see Expectations.java NONCOMPLIANT_FLAG = "Noncompliant" with regex //\s+Noncompliant). NonCompliant (capital C) does not match, so this comment is treated as an ordinary comment. The check still reports a real issue on that fail(); line, which the verifier will now flag as an unexpected issue, causing the test to fail. Additionally, the intended assertion (message text and ^^^^^^ location) is no longer validated. Revert to // Noncompliant.

Quality: Wildcard imports violate rule S2208 (self-dogfooding)

📄 java-checks/src/main/java/org/sonar/java/checks/AssertThrowsInsteadOfTryCatchFailCheck.java:27 📄 java-checks/src/main/java/org/sonar/java/checks/helpers/TryCatchUtils.java:20 📄 java-checks/src/main/java/org/sonar/java/checks/helpers/TryCatchUtils.java:22
AssertThrowsInsteadOfTryCatchFailCheck.java:27 (import org.sonar.plugins.java.api.tree.*;) and TryCatchUtils.java:20,22 (...api.tree.*, java.util.*) use wildcard imports. The sonar-java codebase dogfoods rule S2208 ("Wildcard imports should not be used") and elsewhere uses explicit imports. Replace with explicit single-type imports (Arguments, BaseTreeVisitor, BlockTree, MethodTree, Tree, TryStatementTree, etc. and List, Collections).

Bug: Quickfix throws IndexOutOfBounds for try-block fail() without catch

📄 java-checks/src/main/java/org/sonar/java/checks/AssertThrowsInsteadOfTryCatchFailCheck.java:82-96 📄 java-checks/src/main/java/org/sonar/java/checks/AssertThrowsInsteadOfTryCatchFailCheck.java:116 📄 java-checks/src/main/java/org/sonar/java/checks/AssertThrowsInsteadOfTryCatchFailCheck.java:135 📄 java-checks/src/main/java/org/sonar/java/checks/AssertThrowsInsteadOfTryCatchFailCheck.java:156-158
firstCaughtTypeInTry (line 156-158) and the quickfix edit (line 90-93) unconditionally call tryStatement.catches().get(0) / catches().get(size-1). The rule reports fail() in a try block regardless of whether catch clauses exist (e.g. a try { raise(); fail(); } finally { ... } with no catch). For the try-block path, junitReplacement/assertJReplacement call firstCaughtTypeInTry eagerly at lines 116/135 while building Replacements (before withQuickFix), so an empty catches() list will throw IndexOutOfBoundsException during analysis and crash the rule on otherwise valid code. Guard against an empty catch list: skip the quickfix (still report the issue) when tryStatement.catches().isEmpty().

Quality: Leftover debug System.out.println in new test

📄 java-checks/src/test/java/org/sonar/java/checks/helpers/TryCatchUtilsTest.java:39
The new parseTry helper contains a leftover debugging statement System.out.println(compilationUnitTree);. This pollutes test output and serves no purpose in the assertion. Remove it before merging.

Edge Case: AssertJ quickfix misuses non-String fail() argument as fail message

📄 java-checks/src/main/java/org/sonar/java/checks/AssertThrowsInsteadOfTryCatchFailCheck.java:125-139
assertJReplacement (line 131) always treats failArguments.get(0) as the failure message via contentFor(...) and emits .withFailMessage(<arg0>). But the check also matches AssertJ overloads whose first argument is not a String message, e.g. org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown(IllegalStateException.class) (exercised at sample line 66). That produces .withFailMessage(IllegalStateException.class) which does not compile / is semantically wrong. Also failArguments.get(0) assumes at least one argument, which can throw for no-arg AssertJ fail() variants. Consider only emitting withFailMessage(...) when the first argument is a String, and guard against empty arguments.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqube-next
Copy link
Copy Markdown

sonarqube-next Bot commented Jun 8, 2026

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