Skip to content

Commit b0fc70d

Browse files
authored
Sonar codemod for removing unused local variable (#261)
Codemod to remove unused local variables which expression is a variable (`NameExpr`) or just a Literal expression like a single boolean, char, double, integer, long, null, string or a text block string. We are not considering create object expression, method call expressions, condition expressions, etc. because all of them have an expression node and that expression node could result in a method call expression where a process could be performed and deleting it could result on some unexpected behaviors. Examples of unused `LiteralExpr` : * String msg = "my message" * char myChar = 'c'; * int ten = 10; * etc sonar cloud report example: https://sonarcloud.io/project/issues?fileUuids=AYvtrjqJLCzGLicz7Abq&resolved=false&types=CODE_SMELL&id=nahsra_WebGoat_10_23 reference: https://rules.sonarsource.com/java/RSPEC-1481/
1 parent 1beff2a commit b0fc70d

File tree

14 files changed

+860
-6
lines changed

14 files changed

+860
-6
lines changed

core-codemods/src/main/java/io/codemodder/codemods/AddMissingOverrideCodemod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public final class AddMissingOverrideCodemod extends SonarPluginJavaParserChange
2222
@Inject
2323
public AddMissingOverrideCodemod(
2424
@ProvidedSonarScan(ruleId = "java:S1161") final RuleIssues issues) {
25-
super(issues, SimpleName.class, RegionNodeMatcher.MATCHES_START);
25+
super(issues, SimpleName.class);
2626
}
2727

2828
@Override

core-codemods/src/main/java/io/codemodder/codemods/AvoidImplicitPublicConstructorCodemod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public final class AvoidImplicitPublicConstructorCodemod
2727
@Inject
2828
public AvoidImplicitPublicConstructorCodemod(
2929
@ProvidedSonarScan(ruleId = "java:S1118") final RuleIssues issues) {
30-
super(issues, SimpleName.class, RegionNodeMatcher.MATCHES_START);
30+
super(issues, SimpleName.class);
3131
}
3232

3333
@Override

core-codemods/src/main/java/io/codemodder/codemods/FixRedundantStaticOnEnumCodemod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public final class FixRedundantStaticOnEnumCodemod
2020
@Inject
2121
public FixRedundantStaticOnEnumCodemod(
2222
@ProvidedSonarScan(ruleId = "java:S2786") final RuleIssues issues) {
23-
super(issues, EnumDeclaration.class, RegionNodeMatcher.MATCHES_START);
23+
super(issues, EnumDeclaration.class);
2424
}
2525

2626
@Override

core-codemods/src/main/java/io/codemodder/codemods/RemoveRedundantVariableCreationCodemod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public final class RemoveRedundantVariableCreationCodemod
2222
@Inject
2323
public RemoveRedundantVariableCreationCodemod(
2424
@ProvidedSonarScan(ruleId = "java:S1488") final RuleIssues issues) {
25-
super(issues, ObjectCreationExpr.class, RegionNodeMatcher.MATCHES_START);
25+
super(issues, ObjectCreationExpr.class);
2626
}
2727

2828
@Override
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package io.codemodder.codemods;
2+
3+
import com.github.javaparser.ast.CompilationUnit;
4+
import com.github.javaparser.ast.Node;
5+
import com.github.javaparser.ast.NodeList;
6+
import com.github.javaparser.ast.body.VariableDeclarator;
7+
import com.github.javaparser.ast.expr.*;
8+
import io.codemodder.*;
9+
import io.codemodder.providers.sonar.ProvidedSonarScan;
10+
import io.codemodder.providers.sonar.RuleIssues;
11+
import io.codemodder.providers.sonar.SonarPluginJavaParserChanger;
12+
import io.codemodder.providers.sonar.api.Issue;
13+
import java.util.Optional;
14+
import java.util.stream.Collectors;
15+
import javax.inject.Inject;
16+
17+
/**
18+
* Codemod to remove unused local variables which expression is a variable or just a Literal
19+
* expression like a single boolean, char, double, integer, long, null, string or a text block
20+
* string. We are not considering create object expression, method call expressions, condition
21+
* expressions, etc. because all of them have an expression node and that expression node could
22+
* result in a method call expression where a process could be performed and deleting it could
23+
* result on some unexpected behaviors.
24+
*/
25+
@Codemod(
26+
id = "sonar:java/remove-unused-local-variable-s1481",
27+
reviewGuidance = ReviewGuidance.MERGE_WITHOUT_REVIEW,
28+
executionPriority = CodemodExecutionPriority.HIGH)
29+
public final class RemoveUnusedLocalVariableCodemod
30+
extends SonarPluginJavaParserChanger<VariableDeclarator> {
31+
32+
@Inject
33+
public RemoveUnusedLocalVariableCodemod(
34+
@ProvidedSonarScan(ruleId = "java:S1481") final RuleIssues issues) {
35+
super(issues, VariableDeclarator.class);
36+
}
37+
38+
@Override
39+
public boolean onIssueFound(
40+
final CodemodInvocationContext context,
41+
final CompilationUnit cu,
42+
final VariableDeclarator variableDeclarator,
43+
final Issue issue) {
44+
45+
final Optional<Expression> initializer = variableDeclarator.getInitializer();
46+
47+
if (initializer.isPresent()) {
48+
final Expression initializerExpr = initializer.get();
49+
50+
if (initializerExpr instanceof LiteralExpr || initializerExpr instanceof NameExpr) {
51+
final Optional<Node> variableDeclarationExprOptional = variableDeclarator.getParentNode();
52+
53+
if (variableDeclarationExprOptional.isPresent()) {
54+
final VariableDeclarationExpr variableDeclarationExpr =
55+
(VariableDeclarationExpr) variableDeclarationExprOptional.get();
56+
57+
if (1 == variableDeclarationExpr.getVariables().size()) {
58+
variableDeclarationExpr.removeForced();
59+
} else {
60+
final NodeList<VariableDeclarator> variables =
61+
variableDeclarationExpr.getVariables().stream()
62+
.filter(variable -> !variable.equals(variableDeclarator))
63+
.collect(Collectors.toCollection(NodeList::new));
64+
variableDeclarationExpr.setVariables(variables);
65+
}
66+
67+
return true;
68+
}
69+
}
70+
}
71+
72+
return false;
73+
}
74+
}

core-codemods/src/main/java/io/codemodder/codemods/SimplifyRestControllerAnnotationsCodemod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public final class SimplifyRestControllerAnnotationsCodemod
3030
@Inject
3131
public SimplifyRestControllerAnnotationsCodemod(
3232
@ProvidedSonarScan(ruleId = "java:S6833") final RuleIssues issues) {
33-
super(issues, ClassOrInterfaceDeclaration.class, RegionNodeMatcher.MATCHES_START);
33+
super(issues, ClassOrInterfaceDeclaration.class);
3434
}
3535

3636
@Override

core-codemods/src/main/java/io/codemodder/codemods/SubstituteReplaceAllCodemod.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public final class SubstituteReplaceAllCodemod extends SonarPluginJavaParserChan
1919
@Inject
2020
public SubstituteReplaceAllCodemod(
2121
@ProvidedSonarScan(ruleId = "java:S5361") final RuleIssues issues) {
22-
super(issues, SimpleName.class, RegionNodeMatcher.MATCHES_START);
22+
super(issues, SimpleName.class);
2323
}
2424

2525
@Override
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
This change removes unused variables. Unused variables make the code harder to read, which will lead to confusion and bugs. We only remove variables that have no state-changing effects.
2+
3+
Our changes look something like this:
4+
5+
```diff
6+
catch (final UnsolvedSymbolException e) {
7+
- String errorMessage = "An unexpected exception happened";
8+
LOG.error("Problem resolving type of : {}", expr, e);
9+
return false;
10+
}
11+
```
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"summary" : "Removed unused local variable (Sonar)",
3+
"change" : "Removed unused local variable",
4+
"references" : [
5+
"https://rules.sonarsource.com/java/RSPEC-1481/"
6+
]
7+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.codemodder.codemods;
2+
3+
import io.codemodder.testutils.CodemodTestMixin;
4+
import io.codemodder.testutils.Metadata;
5+
6+
@Metadata(
7+
codemodType = RemoveUnusedLocalVariableCodemod.class,
8+
testResourceDir = "remove-unused-local-variable-s1481",
9+
renameTestFile =
10+
"src/main/java/org/owasp/webgoat/container/assignments/AssignmentEndpoint.java",
11+
dependencies = {})
12+
final class RemoveUnusedLocalVariableCodemodTest implements CodemodTestMixin {}

0 commit comments

Comments
 (0)