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
new file mode 100644
index 0000000000..8854e07dbb
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocations.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java.migrate.lang.var;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.openrewrite.*;
+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;
+
+public class UseVarForGenericMethodInvocations extends Recipe {
+ @Override
+ public String getDisplayName() {
+ //language=markdown
+ return "Apply `var` to Generic Method Invocations";
+ }
+
+ @Override
+ public String getDescription() {
+ //language=markdown
+ return "Apply `var` to variables initialized by invocations of Generic Methods. " +
+ "This recipe ignores generic factory methods without parameters, because open rewrite cannot handle them correctly ATM.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(
+ new UsesJavaVersion<>(10),
+ new UseVarForGenericMethodInvocations.UseVarForGenericsVisitor());
+ }
+
+ 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);
+
+ boolean isGeneralApplicable = DeclarationCheck.isVarApplicable(this.getCursor(), vd);
+ if (!isGeneralApplicable) return vd;
+
+ // recipe specific
+ boolean isPrimitive = DeclarationCheck.isPrimitive(vd);
+ boolean usesNoGenerics = !DeclarationCheck.useGenerics(vd);
+ boolean usesTernary = DeclarationCheck.initializedByTernary(vd);
+ if (isPrimitive || usesTernary || usesNoGenerics) return vd;
+
+ //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
+ boolean hasNoTypeParams = ((J.MethodInvocation) initializer).getTypeParameters() == null;
+ boolean argumentsEmpty = ((J.MethodInvocation) initializer).getArguments().stream().allMatch(p -> p instanceof J.Empty);
+ if (hasNoTypeParams && argumentsEmpty) return vd;
+
+ return transformToVar(vd, new ArrayList<>(), new ArrayList<>());
+ }
+
+ 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 = leftTypes.stream()
+ .map(t ->
+ new J.Identifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, ((JavaType.Class)t).getClassName(), t, null))
+ .collect(Collectors.toList());
+ 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
new file mode 100644
index 0000000000..384867ef87
--- /dev/null
+++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructors.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java.migrate.lang.var;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.openrewrite.*;
+import org.openrewrite.internal.lang.Nullable;
+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;
+
+public class UseVarForGenericsConstructors extends Recipe {
+ @Override
+ public String getDisplayName() {
+ //language=markdown
+ return "Apply `var` to Generic Constructors";
+ }
+
+ @Override
+ public String getDescription() {
+ //language=markdown
+ return "Apply `var` to generics variables initialized by constructor calls.";
+ }
+
+ @Override
+ public TreeVisitor, ExecutionContext> getVisitor() {
+ return Preconditions.check(
+ new UsesJavaVersion<>(10),
+ new UseVarForGenericsConstructors.UseVarForGenericsVisitor());
+ }
+
+ 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);
+
+ boolean isGeneralApplicable = DeclarationCheck.isVarApplicable(this.getCursor(), vd);
+ if (!isGeneralApplicable) return vd;
+
+ // recipe specific
+ boolean isPrimitive = DeclarationCheck.isPrimitive(vd);
+ boolean usesNoGenerics = !DeclarationCheck.useGenerics(vd);
+ boolean usesTernary = DeclarationCheck.initializedByTernary(vd);
+ if (isPrimitive || usesTernary || usesNoGenerics) return vd;
+
+ //now we deal with generics
+ J.VariableDeclarations.NamedVariable variable = vd.getVariables().get(0);
+ List leftTypes = extractParameters(variable.getVariableType());
+ List rightTypes = extractParameters(variable.getInitializer());
+ if (rightTypes == null || (leftTypes.isEmpty() && rightTypes.isEmpty())) return vd;
+
+ return transformToVar(vd, leftTypes, rightTypes);
+ }
+
+ /**
+ * Tries to extract the genric parameters from the expression,
+ * if the Initializer is no new class or not of a parameterized type, returns null to signale "no info".
+ * if the initializer uses empty diamonds use an empty list to signale no type information
+ * @param initializer to extract parameters from
+ * @return null or list of type parameters in diamond
+ */
+ private @Nullable List extractParameters(@Nullable Expression initializer) {
+ if (initializer instanceof J.NewClass) {
+ TypeTree clazz = ((J.NewClass) initializer).getClazz();
+ if (clazz instanceof J.ParameterizedType) {
+ List typeParameters = ((J.ParameterizedType) clazz).getTypeParameters();
+ if (typeParameters != null) {
+ return typeParameters
+ .stream()
+ .map(Expression::getType)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ } else {
+ return new ArrayList<>();
+ }
+ }
+ }
+ return null;
+ }
+
+ private List extractParameters(@Nullable JavaType.Variable variableType) {
+ if (variableType != null && variableType.getType() instanceof JavaType.Parameterized) {
+ return ((JavaType.Parameterized) variableType.getType()).getTypeParameters();
+ } else {
+ return new ArrayList<>();
+ }
+ }
+
+ 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 = leftTypes.stream()
+ .map(t ->
+ new J.Identifier(Tree.randomId(), Space.EMPTY, Markers.EMPTY, ((JavaType.Class)t).getClassName(), t, null))
+ .collect(Collectors.toList());
+ 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/resources/META-INF/rewrite/java-lang-var.yml b/src/main/resources/META-INF/rewrite/java-lang-var.yml
index d88ae95e61..b63cc81402 100644
--- a/src/main/resources/META-INF/rewrite/java-lang-var.yml
+++ b/src/main/resources/META-INF/rewrite/java-lang-var.yml
@@ -17,7 +17,8 @@
type: specs.openrewrite.org/v1beta/recipe
name: org.openrewrite.java.migrate.lang.UseVar
displayName: Use local variable type inference
-description: Apply local variable type inference (`var`) for primitives and objects.
+description: Apply local variable type inference (`var`) for primitives and objects. These recipes can cause unused
+ imports, be advised to run `org.openrewrite.java.RemoveUnusedImports afterwards.
tags:
- refactoring
- java10
@@ -25,3 +26,5 @@ tags:
recipeList:
- org.openrewrite.java.migrate.lang.var.UseVarForObject
- org.openrewrite.java.migrate.lang.var.UseVarForPrimitive
+ - org.openrewrite.java.migrate.lang.var.UseVarForGenericsConstructors
+ - org.openrewrite.java.migrate.lang.var.UseVarForGenericMethodInvocations
diff --git a/src/test/java/org/openrewrite/java/migrate/lang/UseVarKeywordTest.java b/src/test/java/org/openrewrite/java/migrate/lang/UseVarKeywordTest.java
index 0dc9c63ae6..510cc3ce3e 100644
--- a/src/test/java/org/openrewrite/java/migrate/lang/UseVarKeywordTest.java
+++ b/src/test/java/org/openrewrite/java/migrate/lang/UseVarKeywordTest.java
@@ -15,6 +15,9 @@
*/
package org.openrewrite.java.migrate.lang;
+import static org.openrewrite.java.Assertions.java;
+import static org.openrewrite.java.Assertions.version;
+
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -22,9 +25,6 @@
import org.openrewrite.test.RecipeSpec;
import org.openrewrite.test.RewriteTest;
-import static org.openrewrite.java.Assertions.java;
-import static org.openrewrite.java.Assertions.version;
-
class UseVarKeywordTest implements RewriteTest {
@Override
@@ -155,173 +155,6 @@ void m() {
)
);
}
-
- @Nested
- class Generics {
- @Test
- void ifWelldefined() {
- //language=java
- rewriteRun(
- version(
- java("""
- package com.example.app;
-
- import java.util.ArrayList;
-
- class A {
- void m() {
- List strs = new ArrayList();
- }
- }
- """),
- 10
- )
- );
- }
-
- @Test
- void forNoDiamondOperators() {
- //language=java
- rewriteRun(
- version(
- java(
- """
- package com.example.app;
-
- import java.util.ArrayList;
- import java.util.List;
-
- class A {
- void m() {
- List strs = new ArrayList();
- }
- }
- ""","""
- package com.example.app;
-
- import java.util.ArrayList;
- import java.util.List;
-
- class A {
- void m() {
- var strs = new ArrayList();
- }
- }
- """),
- 10
- )
- );
- }
-
- @Test
- void withFactoryMethods() {
- //language=java
- rewriteRun(
- version(
- java(
- """
- package com.example.app;
-
- import java.util.List;
-
- class A {
- void m() {
- List strs = List.of("one", "two");
- }
- }
- """),
- 10
- )
- );
- }
-
- @Test
- void forEmptyFactoryMethod() {
- //language=java
- rewriteRun(
- version(
- java(
- """
- package com.example.app;
-
- import java.util.List;
-
- class A {
- void m() {
- List strs = List.of();
- }
- }
- """),
- 10
- )
- );
- }
-
- @Test
- void withDiamondOperatorOnRaw() {
- //language=java
- rewriteRun(
- version(
- java("""
- package com.example.app;
-
- import java.util.ArrayList;
-
- class A {
- void m() {
- List strs = new ArrayList();
- }
- }
- """),
- 10
- )
- );
- }
-
- @Test
- void withDiamondOperator() {
- //language=java
- rewriteRun(
- version(
- java("""
- package com.example.app;
-
- import java.util.ArrayList;
-
- class A {
- void m() {
- List strs = new ArrayList<>();
- }
- }
- """),
- 10
- )
- );
- }
-
- @Test
- void forEmptyDiamondOperators() {
- //language=java
- rewriteRun(
- version(
- java(
- """
- package com.example.app;
-
- import java.util.ArrayList;
- import java.util.List;
-
- class A {
- void m() {
- List strs = new ArrayList<>();
- }
- }
- """),
- 10
- )
- );
- }
- }
}
@Nested
@@ -800,4 +633,205 @@ void m() {
}
}
}
+
+ @Nested
+ class Generics {
+ @Nested
+ class NotApplicable {
+ @Test
+ void forEmptyFactoryMethod() {
+ //language=java
+ rewriteRun(
+ version(
+ java(
+ """
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ void m() {
+ List strs = List.of();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ @Test
+ void forEmptyDiamondOperators() {
+ //language=java
+ rewriteRun(
+ version(
+ java(
+ """
+ package com.example.app;
+
+ import java.util.ArrayList;
+ import java.util.List;
+
+ class A {
+ void m() {
+ List strs = new ArrayList<>();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ @Test
+ void withDiamondOperatorOnRaw() {
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.ArrayList;
+
+ class A {
+ void m() {
+ List strs = new ArrayList();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ }
+
+ @Nested
+ class Applicable {
+ @Test
+ void ifWelldefined() {
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.ArrayList;
+
+ class A {
+ void m() {
+ List strs = new ArrayList();
+ }
+ }
+ ""","""
+ package com.example.app;
+
+ import java.util.ArrayList;
+
+ class A {
+ void m() {
+ var strs = new ArrayList();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ @Test
+ void forNoDiamondOperators() {
+ //language=java
+ rewriteRun(
+ version(
+ java(
+ """
+ package com.example.app;
+
+ import java.util.ArrayList;
+ import java.util.List;
+
+ class A {
+ void m() {
+ List strs = new ArrayList();
+ }
+ }
+ ""","""
+ package com.example.app;
+
+ import java.util.ArrayList;
+ import java.util.List;
+
+ class A {
+ void m() {
+ var strs = new ArrayList();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ @Test
+ void withDiamondOperator() {
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.List;
+ import java.util.ArrayList;
+
+ class A {
+ void m() {
+ List strs = new ArrayList<>();
+ }
+ }
+ ""","""
+ package com.example.app;
+
+ import java.util.List;
+ import java.util.ArrayList;
+
+ class A {
+ void m() {
+ var strs = new ArrayList();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+
+ @Test
+ @Disabled("not yet implemented by UseVarForMethodInvocations") // todo mboegers in PR #249
+ void withFactoryMethods() {
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ void m() {
+ List strs = List.of("one", "two");
+ }
+ }
+ ""","""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ void m() {
+ List strs = List.of("one", "two");
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ }
+ }
}
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
new file mode 100644
index 0000000000..5e930f074e
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocationsTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.openrewrite.java.migrate.lang.var;
+
+import static org.openrewrite.java.Assertions.*;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+public class UseVarForGenericMethodInvocationsTest implements RewriteTest {
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new UseVarForGenericMethodInvocations())
+ .allSources(s -> s.markers(javaVersion(10)));
+ }
+
+ @Nested
+ class NotApplicable {
+ @Test
+ void forNonGenericMethod() {
+ // this one is handled/covered by UseVarForObjects/Test#staticMethods
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.Arrays;
+ import java.util.List;
+ import java.util.stream.Collectors;
+
+ class A {
+ static String myString(String ... values) {
+ return String.join("",values);
+ }
+ void m() {
+ String strs = myString();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+
+ @Nested
+ class NotSupportedByOpenRewrite {
+ // this is possible because `myList()`s type is fixed to `List` but it is not distinguishable from
+ // a generic method with generic var args like `List.of()`
+ @Test
+ void withStaticMethods() {
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ static List myList() {
+ return List.of("one", "two");
+ }
+ void m() {
+ List strs = myList();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ @Test
+ void withEmptyOnwNonStaticFactoryMethods() {
+ //if detectable this could be `var strs = this.myList();`
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ List myList(T ... values) {
+ return List.of(values);
+ }
+ void m() {
+ List strs = myList();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ @Test
+ void withEmptyOnwFactoryMethods() {
+ // if detectable this could be `var strs = A.myList();`
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ static List myList(T ... values) {
+ return List.of(values);
+ }
+ void m() {
+ List strs = myList();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ @Test
+ void forEmptyJDKFactoryMethod() {
+ // if detectable this could be `var strs = List.of();`
+ //language=java
+ rewriteRun(
+ version(
+ java(
+ """
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ void m() {
+ List strs = List.of();
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ }
+ }
+
+ @Nested
+ class Applicable {
+ @Test
+ void withJDKFactoryMethods() {
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ void m() {
+ List strs = List.of("one", "two");
+ }
+ }
+ ""","""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ void m() {
+ var strs = List.of("one", "two");
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+
+
+
+ @Test
+ void withOwnFactoryMethods() {
+ //language=java
+ rewriteRun(
+ version(
+ java("""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ static List myList(T ... values) {
+ return List.of(values);
+ }
+ void m() {
+ List strs = myList("one", "two");
+ }
+ }
+ ""","""
+ package com.example.app;
+
+ import java.util.List;
+
+ class A {
+ static List myList(T ... values) {
+ return List.of(values);
+ }
+ void m() {
+ var strs = myList("one", "two");
+ }
+ }
+ """),
+ 10
+ )
+ );
+ }
+ }
+}
diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsTest.java
new file mode 100644
index 0000000000..269f9e3227
--- /dev/null
+++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsTest.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2021 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *