Skip to content

Commit 4d6fd83

Browse files
timtebeekclaude
andauthored
Fix RemoveUnusedLocalVariables to preserve assignments with side effects (#741)
* Fix RemoveUnusedLocalVariables to preserve assignments with side effects in try blocks The recipe was incorrectly removing variable assignments in try blocks even when those assignments could throw exceptions and change program behavior. This fix ensures that method invocations within try blocks are preserved since they may throw exceptions that affect control flow. Fixes #740 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Simplify * Avoid making changes when the assignment might have a side effect --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 16dc1da commit 4d6fd83

File tree

2 files changed

+32
-11
lines changed

2 files changed

+32
-11
lines changed

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

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public J.DeconstructionPattern visitDeconstructionPattern(J.DeconstructionPatter
171171
// skip if defined as a parameter to a lambda expression
172172
parent instanceof J.Lambda ||
173173
// skip if the initializer may have a side effect
174-
initializerMightSideEffect(variable)
174+
mightSideEffect(variable.getInitializer())
175175
) {
176176
return variable;
177177
}
@@ -181,6 +181,9 @@ public J.DeconstructionPattern visitDeconstructionPattern(J.DeconstructionPatter
181181
List<Statement> assignmentReferences = VariableReferences.findLhsReferences(parentScope.getValue(), variable.getName());
182182
for (Statement ref : assignmentReferences) {
183183
if (ref instanceof J.Assignment) {
184+
if (mightSideEffect(((J.Assignment) ref).getAssignment())) {
185+
return variable;
186+
}
184187
doAfterVisit(new PruneAssignmentExpression((J.Assignment) ref));
185188
}
186189
doAfterVisit(new DeleteStatement<>(ref));
@@ -216,18 +219,14 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations m
216219
return mv;
217220
}
218221

219-
private boolean initializerMightSideEffect(J.VariableDeclarations.NamedVariable variable) {
220-
if (variable.getInitializer() == null) {
221-
return false;
222-
}
223-
AtomicBoolean mightSideEffect = new AtomicBoolean(false);
224-
new JavaIsoVisitor<AtomicBoolean>() {
222+
private boolean mightSideEffect(Expression initializer) {
223+
return initializer != null && new JavaIsoVisitor<AtomicBoolean>() {
225224
@Override
226225
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation methodInvocation, AtomicBoolean result) {
227226
if (SAFE_GETTER_METHODS.matches(methodInvocation)) {
228227
return methodInvocation;
229228
}
230-
if (withSideEffects == null || Boolean.FALSE.equals(withSideEffects)) {
229+
if (withSideEffects == null || !withSideEffects) {
231230
result.set(true);
232231
}
233232
return methodInvocation;
@@ -244,8 +243,7 @@ public J.Assignment visitAssignment(J.Assignment assignment, AtomicBoolean resul
244243
result.set(true);
245244
return assignment;
246245
}
247-
}.visit(variable.getInitializer(), mightSideEffect);
248-
return mightSideEffect.get();
246+
}.reduce(initializer, new AtomicBoolean(false)).get();
249247
}
250248
});
251249
}

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ static void method() {
704704
try {
705705
used = new Object();
706706
assertEquals(used, null);
707-
unused = new Object();
707+
unused = used;
708708
} catch (Exception e) {
709709
// do nothing
710710
}
@@ -1192,6 +1192,29 @@ void method() {
11921192
);
11931193
}
11941194

1195+
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/740")
1196+
@Test
1197+
void doNotRemoveVariableAssignmentWithPotentialSideEffects() {
1198+
rewriteRun(
1199+
//language=java
1200+
java(
1201+
"""
1202+
class Test {
1203+
private String baz() {
1204+
String foo;
1205+
try {
1206+
foo = String.valueOf(1);
1207+
} catch (RuntimeException e) {
1208+
return "error";
1209+
}
1210+
return "ok";
1211+
}
1212+
}
1213+
"""
1214+
)
1215+
);
1216+
}
1217+
11951218
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/760")
11961219
@Test
11971220
void doNotRemoveUnusedPatternMatchingVariables() {

0 commit comments

Comments
 (0)