Skip to content

Commit 69aeb40

Browse files
authored
Extend UseVarForPrimitive to support String literals (#1024)
* Extend UseVarForPrimitive to also apply var to String literal variables * Simplify * Further simplifications
1 parent 68f9289 commit 69aeb40

2 files changed

Lines changed: 117 additions & 26 deletions

File tree

src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForPrimitive.java

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.openrewrite.java.search.UsesJavaVersion;
2626
import org.openrewrite.java.tree.Expression;
2727
import org.openrewrite.java.tree.J;
28+
import org.openrewrite.java.tree.TypeUtils;
2829

2930
import static java.lang.String.format;
3031
import static org.openrewrite.java.tree.JavaType.Primitive.*;
@@ -33,11 +34,11 @@
3334
@Value
3435
public class UseVarForPrimitive extends Recipe {
3536

36-
String displayName = "Use `var` for primitive-typed variables";
37+
String displayName = "Use `var` for primitive and String variables";
3738

3839

39-
String description = "Try to apply local variable type inference `var` to primitive variables where possible. " +
40-
"This recipe will not touch variable declarations with initializers containing ternary operators.";
40+
String description = "Try to apply local variable type inference `var` to primitive and String literal variables where possible. " +
41+
"This recipe will not touch variable declarations with initializers containing ternary operators.";
4142

4243

4344
@Override
@@ -49,46 +50,45 @@ public TreeVisitor<?, ExecutionContext> getVisitor() {
4950

5051
static final class VarForPrimitivesVisitor extends JavaIsoVisitor<ExecutionContext> {
5152
@Override
52-
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations vd, ExecutionContext ctx) {
53-
vd = super.visitVariableDeclarations(vd, ctx);
53+
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations vardecl, ExecutionContext ctx) {
54+
J.VariableDeclarations vd = super.visitVariableDeclarations(vardecl, ctx);
5455

55-
boolean isGeneralApplicable = DeclarationCheck.isVarApplicable(this.getCursor(), vd);
56-
if (!isGeneralApplicable) {
56+
if (!DeclarationCheck.isVarApplicable(this.getCursor(), vd)) {
5757
return vd;
5858
}
5959

60-
// Recipe specific
61-
boolean isNoPrimitive = !DeclarationCheck.isPrimitive(vd);
62-
boolean isByteVariable = DeclarationCheck.declarationHasType(vd, Byte);
63-
boolean isShortVariable = DeclarationCheck.declarationHasType(vd, Short);
64-
if (isNoPrimitive || isByteVariable || isShortVariable) {
65-
return vd;
60+
if (isStringLiteralInitializer(vd)) {
61+
return DeclarationCheck.transformToVar(vd);
62+
}
63+
if (DeclarationCheck.isPrimitive(vd) &&
64+
!DeclarationCheck.declarationHasType(vd, Byte) &&
65+
!DeclarationCheck.declarationHasType(vd, Short)) {
66+
return DeclarationCheck.transformToVar(vd, it -> it instanceof J.Literal ? expandWithPrimitiveTypeHint(vd, it) : it);
6667
}
68+
return vd;
69+
}
6770

68-
J.VariableDeclarations finalVd = vd;
69-
return DeclarationCheck.transformToVar(vd, it -> it instanceof J.Literal ? expandWithPrimitivTypeHint(finalVd, it) : it);
71+
private boolean isStringLiteralInitializer(J.VariableDeclarations vd) {
72+
if (!TypeUtils.isOfClassType(vd.getType(), "java.lang.String")) {
73+
return false;
74+
}
75+
Expression initializer = vd.getVariables().get(0).getInitializer();
76+
return initializer != null && initializer.unwrap() instanceof J.Literal;
7077
}
7178

72-
private Expression expandWithPrimitivTypeHint(J.VariableDeclarations vd, Expression initializer) {
79+
private Expression expandWithPrimitiveTypeHint(J.VariableDeclarations vd, Expression initializer) {
7380
String valueSource = ((J.Literal) initializer).getValueSource();
7481

7582
if (valueSource == null) {
7683
return initializer;
7784
}
7885

79-
boolean isLongLiteral = Long == vd.getType();
80-
boolean inferredAsLong = valueSource.endsWith("l") || valueSource.endsWith("L");
81-
boolean isFloatLiteral = Float == vd.getType();
82-
boolean inferredAsFloat = valueSource.endsWith("f") || valueSource.endsWith("F");
83-
boolean isDoubleLiteral = Double == vd.getType();
84-
boolean inferredAsDouble = valueSource.endsWith("d") || valueSource.endsWith("D") || valueSource.contains(".");
85-
8686
String typNotation = null;
87-
if (isLongLiteral && !inferredAsLong) {
87+
if (Long == vd.getType() && !(valueSource.endsWith("l") || valueSource.endsWith("L"))) {
8888
typNotation = "L";
89-
} else if (isFloatLiteral && !inferredAsFloat) {
89+
} else if (Float == vd.getType() && !(valueSource.endsWith("f") || valueSource.endsWith("F"))) {
9090
typNotation = "F";
91-
} else if (isDoubleLiteral && !inferredAsDouble) {
91+
} else if (Double == vd.getType() && !(valueSource.endsWith("d") || valueSource.endsWith("D") || valueSource.contains("."))) {
9292
typNotation = "D";
9393
}
9494

src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForPrimitiveTest.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,43 @@ void m() {
6767
)
6868
);
6969
}
70+
71+
@Test
72+
void forStringConcatenation() {
73+
//language=java
74+
rewriteRun(
75+
java(
76+
"""
77+
package com.example.app;
78+
79+
class A {
80+
void m() {
81+
String s = "a" + "b";
82+
}
83+
}
84+
"""
85+
)
86+
);
87+
}
88+
89+
@Test
90+
void forStringMethodCall() {
91+
//language=java
92+
rewriteRun(
93+
java(
94+
"""
95+
package com.example.app;
96+
97+
class A {
98+
String get() { return "hello"; }
99+
void m() {
100+
String s = get();
101+
}
102+
}
103+
"""
104+
)
105+
);
106+
}
70107
}
71108

72109
@Nested
@@ -311,5 +348,59 @@ void m() {
311348
)
312349
);
313350
}
351+
352+
@Test
353+
void forString() {
354+
//language=java
355+
rewriteRun(
356+
java(
357+
"""
358+
package com.example.app;
359+
360+
class A {
361+
void m() {
362+
String s = "hello";
363+
}
364+
}
365+
""",
366+
"""
367+
package com.example.app;
368+
369+
class A {
370+
void m() {
371+
var s = "hello";
372+
}
373+
}
374+
"""
375+
)
376+
);
377+
}
378+
379+
@Test
380+
void forStringWithFinal() {
381+
//language=java
382+
rewriteRun(
383+
java(
384+
"""
385+
package com.example.app;
386+
387+
class A {
388+
void m() {
389+
final String s = "hello";
390+
}
391+
}
392+
""",
393+
"""
394+
package com.example.app;
395+
396+
class A {
397+
void m() {
398+
final var s = "hello";
399+
}
400+
}
401+
"""
402+
)
403+
);
404+
}
314405
}
315406
}

0 commit comments

Comments
 (0)