1919
2020import java .nio .file .Path ;
2121import java .util .ArrayList ;
22+ import java .util .Collections ;
2223import java .util .List ;
2324
2425import org .checkstyle .autofix .PositionHelper ;
3031import org .openrewrite .java .JavaIsoVisitor ;
3132import org .openrewrite .java .tree .J ;
3233import org .openrewrite .java .tree .Space ;
34+ import org .openrewrite .java .tree .Statement ;
3335import 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
0 commit comments