Skip to content

Commit 479580f

Browse files
committed
Issue #80: Resolved MultiVariable declaration Bug
1 parent 00ff3ba commit 479580f

File tree

8 files changed

+208
-28
lines changed

8 files changed

+208
-28
lines changed

src/main/java/org/checkstyle/autofix/recipe/FinalLocalVariable.java

Lines changed: 115 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import java.nio.file.Path;
2121
import java.util.ArrayList;
22+
import java.util.Collections;
2223
import java.util.List;
2324

2425
import org.checkstyle.autofix.PositionHelper;
@@ -30,6 +31,7 @@
3031
import org.openrewrite.java.JavaIsoVisitor;
3132
import org.openrewrite.java.tree.J;
3233
import org.openrewrite.java.tree.Space;
34+
import org.openrewrite.java.tree.Statement;
3335
import org.openrewrite.marker.Markers;
3436

3537
/**
@@ -56,51 +58,140 @@ public String getDescription() {
5658

5759
@Override
5860
public TreeVisitor<?, ExecutionContext> getVisitor() {
59-
return new LocalVariableVisitor();
61+
return new FinalLocalVariableVisitor();
6062
}
6163

62-
private final class LocalVariableVisitor extends JavaIsoVisitor<ExecutionContext> {
64+
private final class FinalLocalVariableVisitor extends JavaIsoVisitor<ExecutionContext> {
6365

6466
private Path sourcePath;
6567

6668
@Override
67-
public J.CompilationUnit visitCompilationUnit(
68-
J.CompilationUnit cu, ExecutionContext executionContext) {
69-
this.sourcePath = cu.getSourcePath();
70-
return super.visitCompilationUnit(cu, executionContext);
69+
public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) {
70+
this.sourcePath = cu.getSourcePath().toAbsolutePath();
71+
return super.visitCompilationUnit(cu, ctx);
7172
}
7273

7374
@Override
7475
public J.VariableDeclarations visitVariableDeclarations(
7576
J.VariableDeclarations multiVariable, ExecutionContext executionContext) {
7677

77-
J.VariableDeclarations declarations = super.visitVariableDeclarations(multiVariable,
78-
executionContext);
78+
final J.VariableDeclarations declarations =
79+
super.visitVariableDeclarations(multiVariable, executionContext);
80+
81+
J.VariableDeclarations result = declarations;
7982

8083
if (!(getCursor().getParentTreeCursor().getValue() instanceof J.ClassDeclaration)
81-
&& declarations.getVariables().size() == 1
82-
&& declarations.getTypeExpression() != null
8384
&& !declarations.hasModifier(J.Modifier.Type.Final)) {
84-
final J.VariableDeclarations.NamedVariable variable = declarations
85-
.getVariables().get(0);
85+
86+
boolean hasViolation = false;
87+
for (J.VariableDeclarations.NamedVariable variable : declarations.getVariables()) {
88+
if (isAtViolationLocation(variable)) {
89+
hasViolation = true;
90+
break;
91+
}
92+
}
93+
94+
if (hasViolation && declarations.getVariables().size() == 1
95+
&& declarations.getTypeExpression() != null) {
96+
result = addFinalModifier(declarations);
97+
}
98+
}
99+
100+
return result;
101+
}
102+
103+
@Override
104+
public J.Block visitBlock(J.Block block, ExecutionContext executionContext) {
105+
J.Block visited = super.visitBlock(block, executionContext);
106+
107+
final List<Statement> newStatements = new ArrayList<>();
108+
boolean changed = false;
109+
110+
for (Statement stmt : visited.getStatements()) {
111+
if (!(stmt instanceof J.VariableDeclarations)) {
112+
newStatements.add(stmt);
113+
continue;
114+
}
115+
116+
final J.VariableDeclarations varDecl = (J.VariableDeclarations) stmt;
117+
118+
if (varDecl.hasModifier(J.Modifier.Type.Final) || getCursor().getParentTreeCursor()
119+
.getValue() instanceof J.ClassDeclaration) {
120+
newStatements.add(stmt);
121+
continue;
122+
}
123+
124+
if (varDecl.getVariables().size() > 1) {
125+
changed |= handleMultiVariableDeclaration(varDecl, newStatements);
126+
}
127+
else {
128+
newStatements.add(stmt);
129+
}
130+
}
131+
132+
if (changed) {
133+
visited = visited.withStatements(newStatements);
134+
}
135+
136+
return visited;
137+
}
138+
139+
private boolean handleMultiVariableDeclaration(J.VariableDeclarations varDecl,
140+
List<Statement> newStatements) {
141+
final List<J.VariableDeclarations.NamedVariable> violationsList = new ArrayList<>();
142+
final List<J.VariableDeclarations.NamedVariable> nonViolations = new ArrayList<>();
143+
144+
for (J.VariableDeclarations.NamedVariable variable : varDecl.getVariables()) {
86145
if (isAtViolationLocation(variable)) {
87-
final List<J.Modifier> modifiers = new ArrayList<>();
88-
modifiers.add(new J.Modifier(Tree.randomId(), Space.EMPTY,
89-
Markers.EMPTY, null, J.Modifier.Type.Final, new ArrayList<>()));
90-
modifiers.addAll(declarations.getModifiers());
91-
declarations = declarations.withModifiers(modifiers)
92-
.withTypeExpression(declarations.getTypeExpression()
93-
.withPrefix(Space.SINGLE_SPACE));
146+
violationsList.add(variable.withPrefix(Space.SINGLE_SPACE));
147+
}
148+
else {
149+
nonViolations.add(variable.withPrefix(Space.SINGLE_SPACE));
150+
}
151+
}
152+
153+
boolean changed = false;
154+
155+
if (violationsList.isEmpty()) {
156+
newStatements.add(varDecl);
157+
}
158+
else if (nonViolations.isEmpty()) {
159+
newStatements.add(addFinalModifier(varDecl));
160+
changed = true;
161+
}
162+
else {
163+
newStatements.add(varDecl.withVariables(nonViolations));
164+
for (J.VariableDeclarations.NamedVariable variable : violationsList) {
165+
newStatements.add(addFinalModifier(varDecl
166+
.withVariables(Collections.singletonList(variable))));
94167
}
168+
changed = true;
169+
}
170+
171+
return changed;
172+
}
173+
174+
private J.VariableDeclarations addFinalModifier(J.VariableDeclarations varDecl) {
175+
final List<J.Modifier> modifiers = new ArrayList<>();
176+
modifiers.add(new J.Modifier(Tree.randomId(), Space.EMPTY,
177+
Markers.EMPTY, null, J.Modifier.Type.Final, new ArrayList<>()));
178+
modifiers.addAll(varDecl.getModifiers());
179+
180+
J.VariableDeclarations result = varDecl.withModifiers(modifiers);
181+
182+
if (result.getTypeExpression() != null) {
183+
result = result.withTypeExpression(
184+
result.getTypeExpression().withPrefix(Space.SINGLE_SPACE));
95185
}
96-
return declarations;
186+
187+
return result;
97188
}
98189

99-
private boolean isAtViolationLocation(J.VariableDeclarations.NamedVariable literal) {
100-
final J.CompilationUnit cursor = getCursor().firstEnclosing(J.CompilationUnit.class);
190+
private boolean isAtViolationLocation(J.VariableDeclarations.NamedVariable variable) {
191+
final J.CompilationUnit cu = getCursor().firstEnclosing(J.CompilationUnit.class);
101192

102-
final int line = PositionHelper.computeLinePosition(cursor, literal, getCursor());
103-
final int column = PositionHelper.computeColumnPosition(cursor, literal, getCursor());
193+
final int line = PositionHelper.computeLinePosition(cu, variable, getCursor());
194+
final int column = PositionHelper.computeColumnPosition(cu, variable, getCursor());
104195

105196
return violations.stream().anyMatch(violation -> {
106197
return violation.getLine() == line

src/test/java/org/checkstyle/autofix/recipe/FinalLocalVariableTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,9 @@ void enhancedForLoop() throws Exception {
4646
verify("EnhancedForLoop");
4747
}
4848

49+
@Test
50+
void multiple() throws Exception {
51+
verify("MultipleVariable");
52+
}
53+
4954
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--- src/test/resources/org/checkstyle/autofix/recipe/finallocalvariable/multiplevariable/InputMultipleVariable.java
2+
+++ src/test/resources/org/checkstyle/autofix/recipe/finallocalvariable/multiplevariable/OutputMultipleVariable.java
3+
@@ -8,15 +8,15 @@
4+
5+
package org.checkstyle.autofix.recipe.finallocalvariable.multiplevariable;
6+
7+
-public class InputMultipleVariable {
8+
+public class OutputMultipleVariable {
9+
10+
public void multipleDeclarations() {
11+
12+
- int x = 10, y = 20, z = 30; // 3 violations
13+
+ final int x = 10, y = 20, z = 30;
14+
15+
- String name = "John", city = "NYC"; // 2 violations
16+
+ final String name = "John", city = "NYC";
17+
18+
- double price = 19.99, tax = 0.08; // 2 violations
19+
+ final double price = 19.99, tax = 0.08;
20+
21+
System.out.println("Sum: " + (x + y + z));
22+
System.out.println(name + " lives in " + city);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*xml
2+
<module name="Checker">
3+
<module name="TreeWalker">
4+
<module name="com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck"/>
5+
</module>
6+
</module>
7+
*/
8+
9+
package org.checkstyle.autofix.recipe.finallocalvariable.multiplevariable;
10+
11+
public class InputMultipleVariable {
12+
13+
public void multipleDeclarations() {
14+
15+
int x = 10, y = 20, z = 30; // 3 violations
16+
17+
String name = "John", city = "NYC"; // 2 violations
18+
19+
double price = 19.99, tax = 0.08; // 2 violations
20+
21+
System.out.println("Sum: " + (x + y + z));
22+
System.out.println(name + " lives in " + city);
23+
System.out.println("Total: " + (price + (price * tax)));
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*xml
2+
<module name="Checker">
3+
<module name="TreeWalker">
4+
<module name="com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck"/>
5+
</module>
6+
</module>
7+
*/
8+
9+
package org.checkstyle.autofix.recipe.finallocalvariable.multiplevariable;
10+
11+
public class OutputMultipleVariable {
12+
13+
public void multipleDeclarations() {
14+
15+
final int x = 10, y = 20, z = 30;
16+
17+
final String name = "John", city = "NYC";
18+
19+
final double price = 19.99, tax = 0.08;
20+
21+
System.out.println("Sum: " + (x + y + z));
22+
System.out.println(name + " lives in " + city);
23+
System.out.println("Total: " + (price + (price * tax)));
24+
}
25+
}

src/test/resources/org/checkstyle/autofix/recipe/finallocalvariable/singlelocaltest/DiffSingleLocalTest.diff

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
--- src/test/resources/org/checkstyle/autofix/recipe/finallocalvariable/singlelocaltest/InputSingleLocalTest.java
22
+++ src/test/resources/org/checkstyle/autofix/recipe/finallocalvariable/singlelocaltest/OutputSingleLocalTest.java
3-
@@ -15,36 +15,35 @@
3+
@@ -15,37 +15,37 @@
44
import java.util.HashMap;
55
import java.util.List;
66

@@ -53,9 +53,12 @@
5353
- String trimmed = input.trim(); // violation, "should be declared final"
5454
- String upperCase = trimmed.toUpperCase(); // violation, "should be declared final"
5555
- String formatted = "[" + upperCase + "]"; // violation, "should be declared final"
56+
- int a,b; // violation, "should be declared final"
5657
+ final String trimmed = input.trim();
5758
+ final String upperCase = trimmed.toUpperCase();
5859
+ final String formatted = "[" + upperCase + "]";
59-
return formatted;
60-
}
61-
60+
+ int a;
61+
+ final int b;
62+
a = upperCase.indexOf(formatted);
63+
b = upperCase.indexOf(formatted);
64+
a = a + formatted.length();

src/test/resources/org/checkstyle/autofix/recipe/finallocalvariable/singlelocaltest/InputSingleLocalTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ public String processResult(String input) {
4545
String trimmed = input.trim(); // violation, "should be declared final"
4646
String upperCase = trimmed.toUpperCase(); // violation, "should be declared final"
4747
String formatted = "[" + upperCase + "]"; // violation, "should be declared final"
48+
int a,b; // violation, "should be declared final"
49+
a = upperCase.indexOf(formatted);
50+
b = upperCase.indexOf(formatted);
51+
a = a + formatted.length();
4852
return formatted;
4953
}
5054

src/test/resources/org/checkstyle/autofix/recipe/finallocalvariable/singlelocaltest/OutputSingleLocalTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ public String processResult(String input) {
4444
final String trimmed = input.trim();
4545
final String upperCase = trimmed.toUpperCase();
4646
final String formatted = "[" + upperCase + "]";
47+
int a;
48+
final int b;
49+
a = upperCase.indexOf(formatted);
50+
b = upperCase.indexOf(formatted);
51+
a = a + formatted.length();
4752
return formatted;
4853
}
4954

0 commit comments

Comments
 (0)