You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adds an UnnecessaryFinalInTryWithResources recipe that removes the redundant final modifier from resources declared in a try-with-resources statement. Such resources are implicitly final (JLS 14.20.3), so the modifier adds no meaning.
Per @greg-at-moderne's feedback, the two overlap but are not the same thing:
NoFinalizedLocalVariables is a stylistic preference — it strips final from every local variable (and optionally parameters), where the modifier is meaningful. It is opt-in and belongs to no composite recipe.
This recipe only touches the one position where final is provably redundant by the language spec, so it changes nothing about what the code means.
Also per that feedback, the recipe was renamed from the original CleanupTryWithResources — "cleanup" didn't say what it did — to UnnecessaryFinalInTryWithResources, matching the neighbouring UnnecessaryCloseInTryWithResources.
Implementation
Java-only: the visitor is gated behind Preconditions.check(new JavaFileChecker<>(), ...).
Only J.Try.Resource declarations are visited, so final on ordinary local variables is untouched.
A final modifier carrying its own annotations is left alone, since dropping it would lose them.
Formatting is preserved deliberately, since final owns whitespace and can carry comments:
comments in the removed modifier's prefix are concatenated onto the following token (type expression, or the variable name when the type is implicit) in source order;
a declaration that was wrapped across lines around final is collapsed back onto one line, but only the gap before each variable name — the initializer keeps its own layout, so a multi-line new ...(...) is not reflowed;
when final leads the declaration its whitespace is dropped entirely; behind a leading annotation the gap belongs to the annotation and survives.
estimatedEffortPerOccurrence is 1 minute. No RSPEC tag — this is not backed by a SonarQube rule.
Registered in META-INF/rewrite/recipes.csv; intentionally not added to common-static-analysis.yml, per the repo convention that the file holds proven recipes only.
BTW, we already have NoFinalizedLocalVariables which does something similar. Or the same thing, but with broader scope. I am not sure yet, how to proceed. Probably just have the new recipe as you suggest.
The name is too generic though. "Cleanup" doesn't necessarily tell the user what it does.
BTW, we already have NoFinalizedLocalVariables which does something similar. Or the same thing, but with broader scope. I am not sure yet, how to proceed. Probably just have the new recipe as you suggest.
The name is too generic though. "Cleanup" doesn't necessarily tell the user what it does.
I pushed an update. Recipe has been renamed to UnnecessaryFinalInTryWithResources
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an
UnnecessaryFinalInTryWithResourcesrecipe that removes the redundantfinalmodifier from resources declared in a try-with-resources statement. Such resources are implicitly final (JLS 14.20.3), so the modifier adds no meaning.Relationship to
NoFinalizedLocalVariablesPer @greg-at-moderne's feedback, the two overlap but are not the same thing:
NoFinalizedLocalVariablesis a stylistic preference — it stripsfinalfrom every local variable (and optionally parameters), where the modifier is meaningful. It is opt-in and belongs to no composite recipe.finalis provably redundant by the language spec, so it changes nothing about what the code means.Also per that feedback, the recipe was renamed from the original
CleanupTryWithResources— "cleanup" didn't say what it did — toUnnecessaryFinalInTryWithResources, matching the neighbouringUnnecessaryCloseInTryWithResources.Implementation
Preconditions.check(new JavaFileChecker<>(), ...).J.Try.Resourcedeclarations are visited, sofinalon ordinary local variables is untouched.finalmodifier carrying its own annotations is left alone, since dropping it would lose them.finalowns whitespace and can carry comments:finalis collapsed back onto one line, but only the gap before each variable name — the initializer keeps its own layout, so a multi-linenew ...(...)is not reflowed;finalleads the declaration its whitespace is dropped entirely; behind a leading annotation the gap belongs to the annotation and survives.estimatedEffortPerOccurrenceis 1 minute. No RSPEC tag — this is not backed by a SonarQube rule.META-INF/rewrite/recipes.csv; intentionally not added tocommon-static-analysis.yml, per the repo convention that the file holds proven recipes only.Tests
UnnecessaryFinalInTryWithResourcesTest, 12 cases:removeFinalModifier(@DocumentExample)varremoveFinalWithExplicitTypevarcleanupMultilineremoveFinalFromEachOfMultipleResourcesfinalremoveFinalOnlyFromTheResourceThatHasItfinalretainLeadingAnnotationWhenRemovingFinalretainCommentBetweenFinalAndTypefinaland the typeretainCommentBetweenAnnotationAndFinalfinalretainLineCommentAndItsLineBreakdoNotReflowInitializerAcrossLinesdoNotChangeResourceWithoutFinaldoNotChangeResourceReferencingExistingVariabletry (existingVar)🤖 Generated with Claude Code