diff --git a/src/main/java/org/openrewrite/java/migrate/lang/var/DeclarationCheck.java b/src/main/java/org/openrewrite/java/migrate/lang/var/DeclarationCheck.java
index 434eee2e3c..b58571ab59 100644
--- a/src/main/java/org/openrewrite/java/migrate/lang/var/DeclarationCheck.java
+++ b/src/main/java/org/openrewrite/java/migrate/lang/var/DeclarationCheck.java
@@ -15,20 +15,27 @@
*/
package org.openrewrite.java.migrate.lang.var;
+import lombok.experimental.UtilityClass;
import org.jspecify.annotations.Nullable;
import org.openrewrite.Cursor;
+import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.tree.*;
+import org.openrewrite.marker.Markers;
+import java.util.List;
+import java.util.function.UnaryOperator;
+
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singleton;
import static java.util.Objects.requireNonNull;
+import static org.openrewrite.Tree.randomId;
+import static org.openrewrite.java.tree.Space.EMPTY;
+@UtilityClass
final class DeclarationCheck {
- private DeclarationCheck() {
-
- }
-
/**
- * Determine if var is applicable with regard to location and decleation type.
+ * Determine if var is applicable with regard to location and declaration type.
*
* Var is applicable inside methods and initializer blocks for single variable definition.
* Var is *not* applicable to method definitions.
@@ -119,7 +126,7 @@ public static boolean useGenerics(J.VariableDeclarations vd) {
}
/**
- * Determin if the initilizer uses the ternary operator Expression ? if-then : else
+ * Determine if the initializer uses the ternary operator Expression ? if-then : else
*
* @param vd variable declaration at hand
* @return true iff the ternary operator is used in the initialization
@@ -225,4 +232,29 @@ public static boolean initializedByStaticMethod(@Nullable Expression initializer
return invocation.getMethodType().hasFlags(Flag.Static);
}
+
+ public static J.VariableDeclarations transformToVar(J.VariableDeclarations vd) {
+ return transformToVar(vd, it -> it);
+ }
+
+ public static J.VariableDeclarations transformToVar(J.VariableDeclarations vd, UnaryOperator transformerInitializer) {
+ T initializer = (T) vd.getVariables().get(0).getInitializer();
+ if (initializer == null) {
+ return vd;
+ }
+
+ Expression transformedInitializer = transformerInitializer.apply(initializer);
+
+ List variables = ListUtils.mapFirst(vd.getVariables(), it -> {
+ JavaType.Variable variableType = it.getVariableType() == null ? null : it.getVariableType().withOwner(null);
+ return it
+ .withName(it.getName().withType(transformedInitializer.getType()).withFieldType(variableType))
+ .withInitializer(transformedInitializer)
+ .withVariableType(variableType);
+ });
+ J.Identifier typeExpression = new J.Identifier(randomId(), vd.getTypeExpression() == null ? EMPTY : vd.getTypeExpression().getPrefix(),
+ Markers.build(singleton(JavaVarKeyword.build())), emptyList(), "var", transformedInitializer.getType(), null);
+
+ return vd.withVariables(variables).withTypeExpression(typeExpression);
+ }
}
diff --git a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocations.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocations.java
index 5754427dbf..376c67d018 100644
--- a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocations.java
+++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocations.java
@@ -15,18 +15,15 @@
*/
package org.openrewrite.java.migrate.lang.var;
-import org.openrewrite.*;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
-import org.openrewrite.java.JavaParser;
-import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.search.UsesJavaVersion;
-import org.openrewrite.java.tree.*;
-import org.openrewrite.marker.Markers;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static java.util.Collections.emptyList;
+import org.openrewrite.java.tree.Expression;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
public class UseVarForGenericMethodInvocations extends Recipe {
@Override
@@ -50,9 +47,6 @@ public TreeVisitor, ExecutionContext> getVisitor() {
}
static final class UseVarForGenericsVisitor extends JavaIsoVisitor {
- private final JavaTemplate template = JavaTemplate.builder("var #{} = #{any()}")
- .javaParser(JavaParser.fromJavaVersion()).build();
-
@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations vd, ExecutionContext ctx) {
vd = super.visitVariableDeclarations(vd, ctx);
@@ -62,7 +56,7 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
return vd;
}
- // recipe specific
+ // Recipe specific
boolean isPrimitive = DeclarationCheck.isPrimitive(vd);
boolean usesNoGenerics = !DeclarationCheck.useGenerics(vd);
boolean usesTernary = DeclarationCheck.initializedByTernary(vd);
@@ -70,26 +64,34 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
return vd;
}
- //now we deal with generics, check for method invocations
+ // Now we deal with generics, check for method invocations
Expression initializer = vd.getVariables().get(0).getInitializer();
boolean isMethodInvocation = initializer != null && initializer.unwrap() instanceof J.MethodInvocation;
if (!isMethodInvocation) {
return vd;
}
- //if no type paramters are present and no arguments we assume the type is hard to determine a needs manual action
+ // If no type parameters and no arguments are present, we assume the type is too hard to determine
boolean hasNoTypeParams = ((J.MethodInvocation) initializer).getTypeParameters() == null;
boolean argumentsEmpty = allArgumentsEmpty((J.MethodInvocation) initializer);
if (hasNoTypeParams && argumentsEmpty) {
return vd;
}
- // mark imports for removal if unused
if (vd.getType() instanceof JavaType.FullyQualified) {
- maybeRemoveImport( (JavaType.FullyQualified) vd.getType() );
+ maybeRemoveImport((JavaType.FullyQualified) vd.getType());
}
- return transformToVar(vd, new ArrayList<>(), new ArrayList<>());
+ return DeclarationCheck.transformToVar(vd);
+ // TODO implement to support cases like `var strs = List.of();`
+ /*J.VariableDeclarations finalVd = vd;
+ return DeclarationCheck.transformToVar(vd, it -> {
+ // If left has generics but right has not, copy types parameters
+ if (finalVd.getTypeExpression() instanceof J.ParameterizedType && !((J.ParameterizedType) finalVd.getTypeExpression()).getTypeParameters().isEmpty() && it.getTypeParameters() == null) {
+ return it.withTypeParameters(((J.ParameterizedType) finalVd.getTypeExpression()).getPadding().getTypeParameters());
+ }
+ return it;
+ });*/
}
private static boolean allArgumentsEmpty(J.MethodInvocation invocation) {
@@ -100,40 +102,5 @@ private static boolean allArgumentsEmpty(J.MethodInvocation invocation) {
}
return true;
}
-
- private J.VariableDeclarations transformToVar(J.VariableDeclarations vd, List leftTypes, List rightTypes) {
- Expression initializer = vd.getVariables().get(0).getInitializer();
- String simpleName = vd.getVariables().get(0).getSimpleName();
-
- // if left is defined but not right, copy types to initializer
- if (rightTypes.isEmpty() && !leftTypes.isEmpty()) {
- // we need to switch type infos from left to right here
- List typeArgument = new ArrayList<>();
- for (JavaType t : leftTypes) {
- typeArgument.add(new J.Identifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), ((JavaType.Class) t).getClassName(), t, null));
- }
- J.ParameterizedType typedInitializerClazz = ((J.ParameterizedType) ((J.NewClass) initializer).getClazz()).withTypeParameters(typeArgument);
- initializer = ((J.NewClass) initializer).withClazz(typedInitializerClazz);
- }
-
- J.VariableDeclarations result = template.apply(getCursor(), vd.getCoordinates().replace(), simpleName, initializer)
- .withPrefix(vd.getPrefix());
-
- // apply modifiers like final
- List modifiers = vd.getModifiers();
- boolean hasModifiers = !modifiers.isEmpty();
- if (hasModifiers) {
- result = result.withModifiers(modifiers);
- }
-
- // apply prefix to type expression
- TypeTree resultingTypeExpression = result.getTypeExpression();
- boolean resultHasTypeExpression = resultingTypeExpression != null;
- if (resultHasTypeExpression) {
- result = result.withTypeExpression(resultingTypeExpression.withPrefix(vd.getTypeExpression().getPrefix()));
- }
-
- return result;
- }
}
}
diff --git a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructors.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructors.java
index 1c7257a383..5a85f3fbf4 100644
--- a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructors.java
+++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructors.java
@@ -20,19 +20,15 @@
import org.openrewrite.Preconditions;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
-import org.openrewrite.internal.ListUtils;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.search.UsesJavaVersion;
-import org.openrewrite.java.tree.*;
-import org.openrewrite.marker.Markers;
+import org.openrewrite.java.tree.Expression;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.TypeTree;
import java.util.ArrayList;
import java.util.List;
-import java.util.Objects;
-
-import static java.util.Collections.emptyList;
-import static java.util.Collections.singleton;
-import static org.openrewrite.Tree.randomId;
public class UseVarForGenericsConstructors extends Recipe {
@Override
@@ -87,12 +83,20 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
return vd;
}
- // Mark imports for removal if unused
if (vd.getType() instanceof JavaType.FullyQualified) {
maybeRemoveImport((JavaType.FullyQualified) vd.getType());
}
- return transformToVar(vd, leftTypes, rightTypes);
+ J.VariableDeclarations finalVd = vd;
+ return DeclarationCheck.transformToVar(vd, it -> {
+ // If left is defined but right is not, copy types from typeExpression to initializer
+ if (rightTypes.isEmpty() && !leftTypes.isEmpty() && finalVd.getTypeExpression() instanceof J.ParameterizedType && it.getClazz() instanceof J.ParameterizedType) {
+ J.ParameterizedType typedInitializerClazz = ((J.ParameterizedType) it.getClazz())
+ .withTypeParameters(((J.ParameterizedType) finalVd.getTypeExpression()).getTypeParameters());
+ return it.withClazz(typedInitializerClazz);
+ }
+ return it;
+ });
}
private static Boolean anyTypeHasBounds(List leftTypes) {
@@ -141,30 +145,5 @@ private List extractTypeParameters(JavaType.@Nullable Variable variabl
}
return new ArrayList<>();
}
-
- private J.VariableDeclarations transformToVar(J.VariableDeclarations vd, List leftTypes, List rightTypes) {
- J.NewClass initializer = Objects.requireNonNull((J.NewClass) vd.getVariables().get(0).getInitializer());
-
- // If left is defined but right is not, copy types from typeExpression to initializer
- if (rightTypes.isEmpty() && !leftTypes.isEmpty() && vd.getTypeExpression() instanceof J.ParameterizedType && initializer.getClazz() instanceof J.ParameterizedType) {
- J.ParameterizedType typedInitializerClazz = ((J.ParameterizedType) initializer.getClazz())
- .withTypeParameters(((J.ParameterizedType) vd.getTypeExpression()).getTypeParameters());
- initializer = initializer.withClazz(typedInitializerClazz);
- }
-
- // Replace actual type by `var` keyword and replace the first variable's name, initializer and type
- J.NewClass finalInitializer = initializer;
- List variables = ListUtils.mapFirst(vd.getVariables(), it -> {
- JavaType.Variable variableType = it.getVariableType() == null ? null : it.getVariableType().withOwner(null);
- return it
- .withName(it.getName().withType(finalInitializer.getType()).withFieldType(variableType))
- .withInitializer(finalInitializer)
- .withVariableType(variableType);
- });
- J.Identifier typeExpression = new J.Identifier(randomId(), vd.getTypeExpression().getPrefix(),
- Markers.build(singleton(JavaVarKeyword.build())), emptyList(), "var", initializer.getType(), null);
-
- return vd.withVariables(variables).withTypeExpression(typeExpression);
- }
}
}
diff --git a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForObject.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForObject.java
index 1b2d9b1feb..1f3de88cd0 100644
--- a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForObject.java
+++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForObject.java
@@ -22,13 +22,10 @@
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
-import org.openrewrite.java.JavaParser;
-import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.search.UsesJavaVersion;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
-import org.openrewrite.java.tree.TypeTree;
@EqualsAndHashCode(callSuper = false)
@Value
@@ -58,11 +55,6 @@ public TreeVisitor, ExecutionContext> getVisitor() {
static final class UseVarForObjectVisitor extends JavaIsoVisitor {
- private final JavaTemplate template = JavaTemplate.builder("var #{} = #{any()};")
- .contextSensitive()
- .javaParser(JavaParser.fromJavaVersion()).build();
-
-
@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations vd, ExecutionContext ctx) {
vd = super.visitVariableDeclarations(vd, ctx);
@@ -82,30 +74,11 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
return vd;
}
- // mark imports for removal if unused
if (vd.getType() instanceof JavaType.FullyQualified) {
maybeRemoveImport( (JavaType.FullyQualified) vd.getType() );
}
- return transformToVar(vd);
- }
-
-
- private J.VariableDeclarations transformToVar(J.VariableDeclarations vd) {
- Expression initializer = vd.getVariables().get(0).getInitializer();
- String simpleName = vd.getVariables().get(0).getSimpleName();
-
- if (vd.getModifiers().isEmpty()) {
- return template.apply(getCursor(), vd.getCoordinates().replace(), simpleName, initializer)
- .withPrefix(vd.getPrefix());
- } else {
- J.VariableDeclarations result = template.apply(getCursor(), vd.getCoordinates().replace(), simpleName, initializer)
- .withModifiers(vd.getModifiers())
- .withPrefix(vd.getPrefix());
- TypeTree typeExpression = result.getTypeExpression();
- //noinspection DataFlowIssue
- return typeExpression != null ? result.withTypeExpression(typeExpression.withPrefix(vd.getTypeExpression().getPrefix())) : vd;
- }
+ return DeclarationCheck.transformToVar(vd);
}
}
}
diff --git a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForPrimitive.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForPrimitive.java
index ac15dc2c6e..03a30ae964 100644
--- a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForPrimitive.java
+++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForPrimitive.java
@@ -22,14 +22,12 @@
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaIsoVisitor;
-import org.openrewrite.java.JavaParser;
-import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.search.UsesJavaVersion;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
-import org.openrewrite.java.tree.JavaType;
import static java.lang.String.format;
+import static org.openrewrite.java.tree.JavaType.Primitive.*;
@EqualsAndHashCode(callSuper = false)
@Value
@@ -58,14 +56,6 @@ public TreeVisitor, ExecutionContext> getVisitor() {
}
static final class VarForPrimitivesVisitor extends JavaIsoVisitor {
-
- private final JavaType.Primitive SHORT_TYPE = JavaType.Primitive.Short;
- private final JavaType.Primitive BYTE_TYPE = JavaType.Primitive.Byte;
-
- private final JavaTemplate template = JavaTemplate.builder("var #{} = #{any()}")
- .javaParser(JavaParser.fromJavaVersion()).build();
-
-
@Override
public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations vd, ExecutionContext ctx) {
vd = super.visitVariableDeclarations(vd, ctx);
@@ -75,41 +65,18 @@ public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations v
return vd;
}
- // recipe specific
+ // Recipe specific
boolean isNoPrimitive = !DeclarationCheck.isPrimitive(vd);
- boolean isByteVariable = DeclarationCheck.declarationHasType(vd, BYTE_TYPE);
- boolean isShortVariable = DeclarationCheck.declarationHasType(vd, SHORT_TYPE);
+ boolean isByteVariable = DeclarationCheck.declarationHasType(vd, Byte);
+ boolean isShortVariable = DeclarationCheck.declarationHasType(vd, Short);
if (isNoPrimitive || isByteVariable || isShortVariable) {
return vd;
}
- // no need to remove imports, because primitives are never imported
-
- return transformToVar(vd);
+ J.VariableDeclarations finalVd = vd;
+ return DeclarationCheck.transformToVar(vd, it -> it instanceof J.Literal ? expandWithPrimitivTypeHint(finalVd, it) : it);
}
-
- private J.VariableDeclarations transformToVar(J.VariableDeclarations vd) {
- Expression initializer = vd.getVariables().get(0).getInitializer();
- String simpleName = vd.getVariables().get(0).getSimpleName();
-
- if (initializer instanceof J.Literal) {
- initializer = expandWithPrimitivTypeHint(vd, initializer);
- }
-
- if (vd.getModifiers().isEmpty()) {
- return template.apply(getCursor(), vd.getCoordinates().replace(), simpleName, initializer)
- .withPrefix(vd.getPrefix());
- } else {
- J.VariableDeclarations result = template.apply(getCursor(), vd.getCoordinates().replace(), simpleName, initializer)
- .withModifiers(vd.getModifiers())
- .withPrefix(vd.getPrefix());
- //noinspection DataFlowIssue
- return result.withTypeExpression(result.getTypeExpression().withPrefix(vd.getTypeExpression().getPrefix()));
- }
- }
-
-
private Expression expandWithPrimitivTypeHint(J.VariableDeclarations vd, Expression initializer) {
String valueSource = ((J.Literal) initializer).getValueSource();
@@ -117,11 +84,11 @@ private Expression expandWithPrimitivTypeHint(J.VariableDeclarations vd, Express
return initializer;
}
- boolean isLongLiteral = JavaType.Primitive.Long == vd.getType();
+ boolean isLongLiteral = Long == vd.getType();
boolean inferredAsLong = valueSource.endsWith("l") || valueSource.endsWith("L");
- boolean isFloatLiteral = JavaType.Primitive.Float == vd.getType();
+ boolean isFloatLiteral = Float == vd.getType();
boolean inferredAsFloat = valueSource.endsWith("f") || valueSource.endsWith("F");
- boolean isDoubleLiteral = JavaType.Primitive.Double == vd.getType();
+ boolean isDoubleLiteral = Double == vd.getType();
boolean inferredAsDouble = valueSource.endsWith("d") || valueSource.endsWith("D") || valueSource.contains(".");
String typNotation = null;
diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocationsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocationsTest.java
index a71e35514a..78d830b959 100644
--- a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocationsTest.java
+++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocationsTest.java
@@ -85,7 +85,7 @@ void m() {
@Test
void withEmptyOnwNonStaticFactoryMethods() {
- //if detectable this could be `var strs = this.myList();`
+ // TODO: this could be `var strs = this.myList();`
//language=java
rewriteRun(
version(
@@ -110,7 +110,7 @@ void m() {
@Test
void withEmptyOnwFactoryMethods() {
- // if detectable this could be `var strs = A.myList();`
+ // TODO: this could be `var strs = A.myList();`
//language=java
rewriteRun(
version(
@@ -135,7 +135,7 @@ void m() {
@Test
void forEmptyJDKFactoryMethod() {
- // if detectable this could be `var strs = List.of();`
+ // TODO: this could be `var strs = List.of();`
//language=java
rewriteRun(
version(