Skip to content

Commit 480ead1

Browse files
Configurable NoFinalizedLocalVariables for excluding methods parameters (#548)
* Adding provide replication test from issue. * Added additional tests with more nesting of variable declarations and return statements. Modified condition on `RemoveUnneededBlock` to allow for block flattening even if it contains variable declarations as long as it also contains a return (which when combined with `RemoveUnreachableCodeVisitor` should be able to prevent issues that might crop up due to descoping the first block. * Adding test cases and implementation to provide a new `excludeMethodParameters` option to be able to skip the removal of final method / lambda parameters. --------- Co-authored-by: Tim te Beek <[email protected]>
1 parent 649a92b commit 480ead1

File tree

2 files changed

+246
-4
lines changed

2 files changed

+246
-4
lines changed

src/main/java/org/openrewrite/staticanalysis/NoFinalizedLocalVariables.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,27 @@
1515
*/
1616
package org.openrewrite.staticanalysis;
1717

18+
import lombok.EqualsAndHashCode;
19+
import lombok.Value;
20+
import org.jspecify.annotations.Nullable;
1821
import org.openrewrite.*;
1922
import org.openrewrite.internal.ListUtils;
2023
import org.openrewrite.java.JavaIsoVisitor;
2124
import org.openrewrite.java.tree.J;
2225

2326
import java.util.Iterator;
2427

28+
@Value
29+
@EqualsAndHashCode(callSuper = false)
2530
@Incubating(since = "7.0.0")
2631
public class NoFinalizedLocalVariables extends Recipe {
2732

33+
@Option(displayName = "Exclude method parameters",
34+
description = "If true, do not remove final from method parameters.",
35+
required = false)
36+
@Nullable
37+
Boolean excludeMethodParameters;
38+
2839
@Override
2940
public String getDisplayName() {
3041
return "Don't use final on local variables";
@@ -50,6 +61,9 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations m
5061
Tree parent = getCursor().getParentTreeCursor().getValue();
5162
if (parent instanceof J.MethodDeclaration || parent instanceof J.Lambda) {
5263
// this variable is a method parameter or lambda parameter
64+
if (Boolean.TRUE.equals(excludeMethodParameters)) {
65+
return mv;
66+
}
5367
return removeFinal(mv);
5468
}
5569

@@ -62,7 +76,7 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations m
6276
if (next instanceof J.ClassDeclaration || next instanceof J.NewClass) {
6377
// this variable is a field
6478
return mv;
65-
} else if (next instanceof J.MethodDeclaration) {
79+
} else if (next instanceof J.MethodDeclaration || next instanceof J.Lambda) {
6680
return removeFinal(mv);
6781
}
6882
}

src/test/java/org/openrewrite/staticanalysis/NoFinalizedLocalVariablesTest.java

Lines changed: 231 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package org.openrewrite.staticanalysis;
1717

18+
import org.junit.jupiter.api.Nested;
1819
import org.junit.jupiter.api.Test;
1920
import org.openrewrite.DocumentExample;
2021
import org.openrewrite.test.RecipeSpec;
@@ -27,7 +28,7 @@ class NoFinalizedLocalVariablesTest implements RewriteTest {
2728

2829
@Override
2930
public void defaults(RecipeSpec spec) {
30-
spec.recipe(new NoFinalizedLocalVariables());
31+
spec.recipe(new NoFinalizedLocalVariables(null));
3132
}
3233

3334
@DocumentExample
@@ -70,24 +71,251 @@ public String get() {
7071
);
7172
}
7273

74+
@Test
75+
void removeFinalFromWithinTryBlock() {
76+
rewriteRun(
77+
//language=java
78+
java(
79+
"""
80+
class T {
81+
final int field = 0;
82+
public void test(final String s) {
83+
final int n = 0;
84+
try {
85+
final int innerField = 0;
86+
} catch (final RuntimeException e) {
87+
final int inCatchField = 0;
88+
};
89+
}
90+
}
91+
""",
92+
"""
93+
class T {
94+
final int field = 0;
95+
public void test(String s) {
96+
int n = 0;
97+
try {
98+
int innerField = 0;
99+
} catch (RuntimeException e) {
100+
int inCatchField = 0;
101+
};
102+
}
103+
}
104+
"""
105+
)
106+
);
107+
}
108+
73109
@Test
74110
void retainPrefix() {
75111
rewriteRun(
76112
//language=java
77113
java(
78114
"""
79115
class T {
80-
public void test(@SuppressWarnings final String s) {
116+
public void test(@SuppressWarnings("ALL") final String s) {
81117
}
82118
}
83119
""",
84120
"""
85121
class T {
86-
public void test(@SuppressWarnings String s) {
122+
public void test(@SuppressWarnings("ALL") String s) {
87123
}
88124
}
89125
"""
90126
)
91127
);
92128
}
129+
130+
@Nested
131+
class WithExcludeMethodParametersTrue {
132+
@Test
133+
void removesFinalExceptOnMethodParameters() {
134+
rewriteRun(
135+
spec -> spec.recipe(new NoFinalizedLocalVariables(true)),
136+
//language=java
137+
java(
138+
"""
139+
import java.util.function.Function;
140+
import java.util.function.Supplier;
141+
class T {
142+
final int field = 0;
143+
final Function<String, Boolean> lambda = (final String t) -> {
144+
final int j = 1;
145+
return true;
146+
};
147+
public void test(final String s) {
148+
final int n = 0;
149+
new Supplier<>() {
150+
final int innerField = 0;
151+
public String get() {
152+
return s;
153+
}
154+
private void set(final Boolean u) {
155+
final Function<String, Boolean> innerLambda = (final String x) -> {
156+
final int k = 2;
157+
return u;
158+
};
159+
}
160+
};
161+
}
162+
}
163+
""",
164+
"""
165+
import java.util.function.Function;
166+
import java.util.function.Supplier;
167+
class T {
168+
final int field = 0;
169+
final Function<String, Boolean> lambda = (final String t) -> {
170+
int j = 1;
171+
return true;
172+
};
173+
public void test(final String s) {
174+
int n = 0;
175+
new Supplier<>() {
176+
final int innerField = 0;
177+
public String get() {
178+
return s;
179+
}
180+
private void set(final Boolean u) {
181+
Function<String, Boolean> innerLambda = (final String x) -> {
182+
int k = 2;
183+
return u;
184+
};
185+
}
186+
};
187+
}
188+
}
189+
"""
190+
)
191+
);
192+
}
193+
}
194+
195+
@Nested
196+
class WithExcludeMethodParametersFalseOrNull {
197+
@Test
198+
void withFalseRemovesFinal() {
199+
rewriteRun(
200+
spec -> spec.recipe(new NoFinalizedLocalVariables(false)),
201+
//language=java
202+
java(
203+
"""
204+
import java.util.function.Function;
205+
import java.util.function.Supplier;
206+
class T {
207+
final int field = 0;
208+
final Function<String, Boolean> lambda = (final String t) -> {
209+
final int j = 1;
210+
return true;
211+
};
212+
public void test(final String s) {
213+
final int n = 0;
214+
new Supplier<>() {
215+
final int innerField = 0;
216+
public String get() {
217+
return s;
218+
}
219+
private void set(final Boolean u) {
220+
final Function<String, Boolean> innerLambda = (final String x) -> {
221+
final int k = 2;
222+
return u;
223+
};
224+
}
225+
};
226+
}
227+
}
228+
""",
229+
"""
230+
import java.util.function.Function;
231+
import java.util.function.Supplier;
232+
class T {
233+
final int field = 0;
234+
final Function<String, Boolean> lambda = (String t) -> {
235+
int j = 1;
236+
return true;
237+
};
238+
public void test(String s) {
239+
int n = 0;
240+
new Supplier<>() {
241+
final int innerField = 0;
242+
public String get() {
243+
return s;
244+
}
245+
private void set(Boolean u) {
246+
Function<String, Boolean> innerLambda = (String x) -> {
247+
int k = 2;
248+
return u;
249+
};
250+
}
251+
};
252+
}
253+
}
254+
"""
255+
)
256+
);
257+
}
258+
259+
@Test
260+
void withNullRemovesFinal() {
261+
rewriteRun(
262+
spec -> spec.recipe(new NoFinalizedLocalVariables(null)),
263+
//language=java
264+
java(
265+
"""
266+
import java.util.function.Function;
267+
import java.util.function.Supplier;
268+
class T {
269+
final int field = 0;
270+
final Function<String, Boolean> lambda = (final String t) -> {
271+
final int j = 1;
272+
return true;
273+
};
274+
public void test(final String s) {
275+
final int n = 0;
276+
new Supplier<>() {
277+
final int innerField = 0;
278+
public String get() {
279+
return s;
280+
}
281+
private void set(final Boolean u) {
282+
final Function<String, Boolean> innerLambda = (final String x) -> {
283+
final int k = 2;
284+
return u;
285+
};
286+
}
287+
};
288+
}
289+
}
290+
""",
291+
"""
292+
import java.util.function.Function;
293+
import java.util.function.Supplier;
294+
class T {
295+
final int field = 0;
296+
final Function<String, Boolean> lambda = (String t) -> {
297+
int j = 1;
298+
return true;
299+
};
300+
public void test(String s) {
301+
int n = 0;
302+
new Supplier<>() {
303+
final int innerField = 0;
304+
public String get() {
305+
return s;
306+
}
307+
private void set(Boolean u) {
308+
Function<String, Boolean> innerLambda = (String x) -> {
309+
int k = 2;
310+
return u;
311+
};
312+
}
313+
};
314+
}
315+
}
316+
"""
317+
)
318+
);
319+
}
320+
}
93321
}

0 commit comments

Comments
 (0)