From 092762294f86a9e4f067ff5f21e9a49d355b9e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Thu, 29 Jun 2023 14:19:00 +0200 Subject: [PATCH 1/8] fix missing imports in VarBaseTest --- .../java/migrate/lang/var/VarBaseTest.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/VarBaseTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/VarBaseTest.java index 4c5eb38a74..ab75b9d904 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/var/VarBaseTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/VarBaseTest.java @@ -15,13 +15,13 @@ */ package org.openrewrite.java.migrate.lang.var; +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.Assertions.version; + import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.test.RewriteTest; -import static org.openrewrite.java.Assertions.java; -import static org.openrewrite.java.Assertions.version; - abstract class VarBaseTest implements RewriteTest { @Nested class GeneralNotApplicable { @@ -181,9 +181,12 @@ void inDefinition() { java(""" package com.example.app; + import java.util.List; + import java.util.ArrayList; + class A { void m() { - List os = new List(); + List os = new ArrayList<>(); } } """ @@ -197,10 +200,13 @@ void inInitializer() { rewriteRun( java(""" package com.example.app; + + import java.util.ArrayList; + import java.util.List; class A { void m() { - List os = new List(); + List os = new ArrayList(); } } """ From 17d7eef916c1cd67a16ce77c2b2f29dfeab4b04a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Thu, 29 Jun 2023 14:19:42 +0200 Subject: [PATCH 2/8] add Tests to prove issue #236 us already covered (except generics) --- .../lang/var/UseVarForObjectsTest.java | 123 +++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForObjectsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForObjectsTest.java index a3e48f764a..861d4a2192 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForObjectsTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForObjectsTest.java @@ -15,15 +15,14 @@ */ package org.openrewrite.java.migrate.lang.var; +import static org.openrewrite.java.Assertions.*; + import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.DocumentExample; import org.openrewrite.test.RecipeSpec; -import static org.openrewrite.java.Assertions.java; -import static org.openrewrite.java.Assertions.javaVersion; - class UseVarForObjectsTest extends VarBaseTest { public void defaults(RecipeSpec spec) { @@ -181,6 +180,124 @@ class A { ) ); } + + @Nested + class InitilizedByMethod { + @Test + void sameType() { + //language=java + rewriteRun( + version( + java(""" + package com.example.app; + + class A { + String getHello() { + return "Hello"; + } + void m() { + String phrase = getHello(); + } + } + """, """ + package com.example.app; + + class A { + String getHello() { + return "Hello"; + } + void m() { + var phrase = getHello(); + } + } + """), + 10 + ) + ); + } + + @Test + void subType() { + //language=java + rewriteRun( + version( + java(""" + package com.example.app; + + class A { + class CustomTokenizer extends java.util.StringTokenizer { + CustomTokenizer() { + super(""); + } + } + CustomTokenizer getHello() { + return new CustomTokenizer(); + } + void m() { + CustomTokenizer phrase = getHello(); + } + } + """, """ + package com.example.app; + + class A { + class CustomTokenizer extends java.util.StringTokenizer { + CustomTokenizer() { + super(""); + } + } + CustomTokenizer getHello() { + return new CustomTokenizer(); + } + void m() { + var phrase = getHello(); + } + } + """), + 10 + ) + ); + } + + @Test + void staticMethods() { + //language=java + rewriteRun( + version( + java(""" + package com.example.app; + + class A { + static class B { + private B() {} + static B newInstance() { + return new B(); + } + } + void m() { + B b = B.newInstance(); + } + } + """, """ + package com.example.app; + + class A { + static class B { + private B() {} + static B newInstance() { + return new B(); + } + } + void m() { + var b = B.newInstance(); + } + } + """), + 10 + ) + ); + } + } } @Nested From ff62c1449a0e51e67ea11c87aec7aada2a20e17a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Thu, 29 Jun 2023 14:54:43 +0200 Subject: [PATCH 3/8] add new Recipe to cover var for generics add test harness --- .../migrate/lang/var/UseVarForGenerics.java | 55 +++ .../META-INF/rewrite/java-lang-var.yml | 1 + .../java/migrate/lang/UseVarKeywordTest.java | 371 ++++++++++-------- .../lang/var/UseVarForGenericsTest.java | 204 ++++++++++ 4 files changed, 461 insertions(+), 170 deletions(-) create mode 100644 src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java create mode 100644 src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java new file mode 100644 index 0000000000..8314bbfbde --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java @@ -0,0 +1,55 @@ +package org.openrewrite.java.migrate.lang.var; + +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.J; + +public class UseVarForGenerics extends Recipe { + @Override + public String getDisplayName() { + //language=markdown + return "Apply `var` to generic variables"; + } + + @Override + public String getDescription() { + //language=markdown + return "Apply `var` to generics where possible. This recipe covers generic definitions and initializers."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check( + new UsesJavaVersion<>(10), + new UseVarForGenerics.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 + + return vd; + } + } +} 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..64b111b869 100644 --- a/src/main/resources/META-INF/rewrite/java-lang-var.yml +++ b/src/main/resources/META-INF/rewrite/java-lang-var.yml @@ -25,3 +25,4 @@ tags: recipeList: - org.openrewrite.java.migrate.lang.var.UseVarForObject - org.openrewrite.java.migrate.lang.var.UseVarForPrimitive + - org.openrewrite.java.migrate.lang.var.UseVarForGenerics 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..2fe2458df6 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,202 @@ 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.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 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/UseVarForGenericsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java new file mode 100644 index 0000000000..6bdb047e1e --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java @@ -0,0 +1,204 @@ +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 UseVarForGenericsTest implements RewriteTest { + public void defaults(RecipeSpec spec) { + spec.recipe(new UseVarForGenerics()) + .allSources(s -> s.markers(javaVersion(10))); + } + + @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() { + //todo check if this may be possible!, We could transform ArrayList into ArrayList + //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(); + } + } + """), + 10 + ) + ); + } + } + + @Nested + class Applicable { + @Test + void ifWelldefined() { + //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.ArrayList; + + class A { + void m() { + var strs = new ArrayList(); + } + } + """), + 10 + ) + ); + } + @Test + void forNoDiamondOperators() { + // this one fails for generics because it's covered by UseVarForObjects + //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 withDiamondOperator() { + //language=java + rewriteRun( + version( + java(""" + package com.example.app; + + import hava.util.List; + 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 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 + ) + ); + } + } +} From f44eaf38384ba3ceee6c5cfb1c6ded57845218d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Thu, 29 Jun 2023 15:11:35 +0200 Subject: [PATCH 4/8] add missing licences --- .../java/migrate/lang/var/UseVarForGenerics.java | 15 +++++++++++++++ .../migrate/lang/var/UseVarForGenericsTest.java | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java index 8314bbfbde..b98ff761b3 100644 --- a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java +++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java @@ -1,3 +1,18 @@ +/* + * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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 org.openrewrite.ExecutionContext; diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java index 6bdb047e1e..9e07a6c69c 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java @@ -1,3 +1,18 @@ +/* + * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.*; From 5a58c6861afeffcb7fadc247e6ba6c7801ca3a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Fri, 7 Jul 2023 10:36:59 +0200 Subject: [PATCH 5/8] Implement var for generic constructor invocations and move general method invocation to own recipe --- .../migrate/lang/var/UseVarForGenerics.java | 70 ------- .../var/UseVarForGenericsConstructors.java | 147 ++++++++++++++ .../lang/var/UseVarForMethodInvocations.java | 32 +++ .../META-INF/rewrite/java-lang-var.yml | 7 +- ...GenericsConstructorsConstructorsTest.java} | 111 +++++----- .../var/UseVarForMethodInvocationsTest.java | 189 ++++++++++++++++++ 6 files changed, 425 insertions(+), 131 deletions(-) delete mode 100644 src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java create mode 100644 src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructors.java create mode 100644 src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocations.java rename src/test/java/org/openrewrite/java/migrate/lang/var/{UseVarForGenericsTest.java => UseVarForGenericsConstructorsConstructorsTest.java} (91%) create mode 100644 src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocationsTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java deleted file mode 100644 index b98ff761b3..0000000000 --- a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenerics.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * 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 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.J; - -public class UseVarForGenerics extends Recipe { - @Override - public String getDisplayName() { - //language=markdown - return "Apply `var` to generic variables"; - } - - @Override - public String getDescription() { - //language=markdown - return "Apply `var` to generics where possible. This recipe covers generic definitions and initializers."; - } - - @Override - public TreeVisitor getVisitor() { - return Preconditions.check( - new UsesJavaVersion<>(10), - new UseVarForGenerics.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 - - return vd; - } - } -} 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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 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/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocations.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocations.java new file mode 100644 index 0000000000..e3672a74af --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocations.java @@ -0,0 +1,32 @@ +/* + * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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 org.openrewrite.Recipe; + +public class UseVarForMethodInvocations extends Recipe { + @Override + public String getDisplayName() { + //language=markdown + return "Apply `var` to Method Invocations"; + } + + @Override + public String getDescription() { + //language=markdown + return "Apply `var` to variables initialized by invocations of Methods."; + } +} 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 64b111b869..1b1c2dda25 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,4 +26,6 @@ tags: recipeList: - org.openrewrite.java.migrate.lang.var.UseVarForObject - org.openrewrite.java.migrate.lang.var.UseVarForPrimitive - - org.openrewrite.java.migrate.lang.var.UseVarForGenerics + - org.openrewrite.java.migrate.lang.var.UseVarForMethodInvocations + - org.openrewrite.java.migrate.lang.var.UseVarForMethodInvocations + - org.openrewrite.java.migrate.lang.var.UseVarForGenericsConstructors diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsConstructorsTest.java similarity index 91% rename from src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java rename to src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsConstructorsTest.java index 9e07a6c69c..df2965ed63 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsConstructorsTest.java @@ -22,9 +22,9 @@ import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; -public class UseVarForGenericsTest implements RewriteTest { +public class UseVarForGenericsConstructorsConstructorsTest implements RewriteTest { public void defaults(RecipeSpec spec) { - spec.recipe(new UseVarForGenerics()) + spec.recipe(new UseVarForGenericsConstructors()) .allSources(s -> s.markers(javaVersion(10))); } @@ -52,6 +52,27 @@ void m() { ); } @Test + void withFactoryMethods() { + // this one is handled by UseVarForMethodInvocations + //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 forEmptyDiamondOperators() { //language=java rewriteRun( @@ -60,8 +81,8 @@ void forEmptyDiamondOperators() { """ package com.example.app; - import java.util.ArrayList; import java.util.List; + import java.util.ArrayList; class A { void m() { @@ -95,41 +116,6 @@ void m() { ) ); } - } - - @Nested - class Applicable { - @Test - void ifWelldefined() { - //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.ArrayList; - - class A { - void m() { - var strs = new ArrayList(); - } - } - """), - 10 - ) - ); - } @Test void forNoDiamondOperators() { // this one fails for generics because it's covered by UseVarForObjects @@ -140,8 +126,8 @@ void forNoDiamondOperators() { """ package com.example.app; - import java.util.ArrayList; import java.util.List; + import java.util.ArrayList; class A { void m() { @@ -153,25 +139,30 @@ void m() { ) ); } + } + + @Nested + class Applicable { @Test - void withDiamondOperator() { + void ifWelldefined() { //language=java rewriteRun( version( java(""" package com.example.app; - - import hava.util.List; + + import java.util.List; import java.util.ArrayList; class A { void m() { - List strs = new ArrayList<>(); + List strs = new ArrayList(); } } """,""" package com.example.app; - + + import java.util.List; import java.util.ArrayList; class A { @@ -186,31 +177,33 @@ void m() { } @Test - void withFactoryMethods() { + void withTypeParameterInDefinitionOnly() { //language=java rewriteRun( version( java(""" - package com.example.app; + package com.example.app; - import java.util.List; + import java.util.List; + import java.util.ArrayList; - class A { - void m() { - List strs = List.of("one", "two"); + class A { + void m() { + List strs = new ArrayList<>(); + } } - } - """,""" - package com.example.app; + """,""" + package com.example.app; - import java.util.List; + import java.util.List; + import java.util.ArrayList; - class A { - void m() { - List strs = List.of("one", "two"); + class A { + void m() { + var strs = new ArrayList(); + } } - } - """), + """), 10 ) ); diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocationsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocationsTest.java new file mode 100644 index 0000000000..49a7d33361 --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocationsTest.java @@ -0,0 +1,189 @@ +/* + * 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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.Disabled; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +@Disabled("Not yet implemented") +public class UseVarForMethodInvocationsTest implements RewriteTest { + public void defaults(RecipeSpec spec) { + spec.recipe(new UseVarForMethodInvocations()) + .allSources(s -> s.markers(javaVersion(10))); + } + + @Nested + class NotApplicable { + @Test + void forEmptyJDKFactoryMethod() { + //language=java + rewriteRun( + version( + java( + """ + package com.example.app; + + import java.util.List; + + class A { + void m() { + List strs = List.of(); + } + } + """), + 10 + ) + ); + } + + @Test + void withEmptyOnwFactoryMethods() { + //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 + ) + ); + } + } + + @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 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(); + } + } + """,""" + package com.example.app; + + import java.util.List; + + class A { + static List myList() { + return List.of("one", "two"); + } + void m() { + var strs = myList(); + } + } + """), + 10 + ) + ); + } + + @Test + void withOnwFactoryMethods() { + //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 + ) + ); + } + } +} From bd8251040371136f871615aa38ddd109646fdc41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Fri, 7 Jul 2023 10:45:18 +0200 Subject: [PATCH 6/8] Update UseVarKeywordTest to be compliant with child test UseVarForGenericsConstructorsTest --- .../openrewrite/java/migrate/lang/UseVarKeywordTest.java | 7 +++++-- ...orsTest.java => UseVarForGenericsConstructorsTest.java} | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) rename src/test/java/org/openrewrite/java/migrate/lang/var/{UseVarForGenericsConstructorsConstructorsTest.java => UseVarForGenericsConstructorsTest.java} (98%) 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 2fe2458df6..510cc3ce3e 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/UseVarKeywordTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/UseVarKeywordTest.java @@ -775,7 +775,8 @@ void withDiamondOperator() { version( java(""" package com.example.app; - + + import java.util.List; import java.util.ArrayList; class A { @@ -785,7 +786,8 @@ void m() { } """,""" package com.example.app; - + + import java.util.List; import java.util.ArrayList; class A { @@ -800,6 +802,7 @@ void m() { } @Test + @Disabled("not yet implemented by UseVarForMethodInvocations") // todo mboegers in PR #249 void withFactoryMethods() { //language=java rewriteRun( diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsConstructorsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsTest.java similarity index 98% rename from src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsConstructorsTest.java rename to src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsTest.java index df2965ed63..269f9e3227 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsConstructorsTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericsConstructorsTest.java @@ -22,7 +22,7 @@ import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; -public class UseVarForGenericsConstructorsConstructorsTest implements RewriteTest { +public class UseVarForGenericsConstructorsTest implements RewriteTest { public void defaults(RecipeSpec spec) { spec.recipe(new UseVarForGenericsConstructors()) .allSources(s -> s.markers(javaVersion(10))); From 274dbb3d26d609431796aff904064ef558251aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Mon, 10 Jul 2023 09:39:07 +0200 Subject: [PATCH 7/8] Modify Generic Method Invocations * Update name of UseVarForGenericMethodInvocations to reflect action * Fix yml recipe java-lang-var.yml * update tests to reflect shortcomings of open rewrite regarding generic method invocations --- .../UseVarForGenericMethodInvocations.java | 116 ++++++++++++++ .../lang/var/UseVarForMethodInvocations.java | 32 ---- .../META-INF/rewrite/java-lang-var.yml | 3 +- ...seVarForGenericMethodInvocationsTest.java} | 151 +++++++++++------- 4 files changed, 214 insertions(+), 88 deletions(-) create mode 100644 src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocations.java delete mode 100644 src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocations.java rename src/test/java/org/openrewrite/java/migrate/lang/var/{UseVarForMethodInvocationsTest.java => UseVarForGenericMethodInvocationsTest.java} (60%) 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 + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * 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 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/UseVarForMethodInvocations.java b/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocations.java deleted file mode 100644 index e3672a74af..0000000000 --- a/src/main/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocations.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 - *

- * https://www.apache.org/licenses/LICENSE-2.0 - *

- * 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 org.openrewrite.Recipe; - -public class UseVarForMethodInvocations extends Recipe { - @Override - public String getDisplayName() { - //language=markdown - return "Apply `var` to Method Invocations"; - } - - @Override - public String getDescription() { - //language=markdown - return "Apply `var` to variables initialized by invocations of Methods."; - } -} 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 1b1c2dda25..b63cc81402 100644 --- a/src/main/resources/META-INF/rewrite/java-lang-var.yml +++ b/src/main/resources/META-INF/rewrite/java-lang-var.yml @@ -26,6 +26,5 @@ tags: recipeList: - org.openrewrite.java.migrate.lang.var.UseVarForObject - org.openrewrite.java.migrate.lang.var.UseVarForPrimitive - - org.openrewrite.java.migrate.lang.var.UseVarForMethodInvocations - - org.openrewrite.java.migrate.lang.var.UseVarForMethodInvocations - 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/var/UseVarForMethodInvocationsTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocationsTest.java similarity index 60% rename from src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocationsTest.java rename to src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocationsTest.java index 49a7d33361..58e42d518a 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForMethodInvocationsTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/UseVarForGenericMethodInvocationsTest.java @@ -17,59 +17,38 @@ import static org.openrewrite.java.Assertions.*; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; -@Disabled("Not yet implemented") -public class UseVarForMethodInvocationsTest implements RewriteTest { +public class UseVarForGenericMethodInvocationsTest implements RewriteTest { public void defaults(RecipeSpec spec) { - spec.recipe(new UseVarForMethodInvocations()) + spec.recipe(new UseVarForGenericMethodInvocations()) .allSources(s -> s.markers(javaVersion(10))); } @Nested class NotApplicable { @Test - void forEmptyJDKFactoryMethod() { - //language=java - rewriteRun( - version( - java( - """ - package com.example.app; - - import java.util.List; - - class A { - void m() { - List strs = List.of(); - } - } - """), - 10 - ) - ); - } - - @Test - void withEmptyOnwFactoryMethods() { + 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 List myList(T ... values) { - return List.of(values); + static String myString(String ... values) { + return String.join("",values); } void m() { - List strs = myList(); + String strs = myString(); } } """), @@ -77,43 +56,111 @@ void m() { ) ); } - } - @Nested - class Applicable { - @Test - void withJDKFactoryMethods() { - //language=java - rewriteRun( - version( - java(""" + @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 = List.of("one", "two"); + 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() { - var strs = List.of("one", "two"); + List strs = myList(); } } """), - 10 - ) - ); + 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 withStaticMethods() { + void withJDKFactoryMethods() { //language=java rewriteRun( version( @@ -123,11 +170,8 @@ void withStaticMethods() { import java.util.List; class A { - static List myList() { - return List.of("one", "two"); - } void m() { - List strs = myList(); + List strs = List.of("one", "two"); } } """,""" @@ -136,11 +180,8 @@ void m() { import java.util.List; class A { - static List myList() { - return List.of("one", "two"); - } void m() { - var strs = myList(); + var strs = List.of("one", "two"); } } """), @@ -149,6 +190,8 @@ void m() { ); } + + @Test void withOnwFactoryMethods() { //language=java From 400f836f58c61b667fc9710b1a433f87cb14e166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Merlin=20B=C3=B6gershausen?= Date: Mon, 10 Jul 2023 13:42:48 +0200 Subject: [PATCH 8/8] Apply suggestions from code review Co-authored-by: Joan Viladrosa --- .../lang/var/UseVarForGenericMethodInvocationsTest.java | 2 +- .../org/openrewrite/java/migrate/lang/var/VarBaseTest.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) 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 58e42d518a..5e930f074e 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 @@ -193,7 +193,7 @@ void m() { @Test - void withOnwFactoryMethods() { + void withOwnFactoryMethods() { //language=java rewriteRun( version( diff --git a/src/test/java/org/openrewrite/java/migrate/lang/var/VarBaseTest.java b/src/test/java/org/openrewrite/java/migrate/lang/var/VarBaseTest.java index ab75b9d904..81c9772d44 100644 --- a/src/test/java/org/openrewrite/java/migrate/lang/var/VarBaseTest.java +++ b/src/test/java/org/openrewrite/java/migrate/lang/var/VarBaseTest.java @@ -15,8 +15,7 @@ */ package org.openrewrite.java.migrate.lang.var; -import static org.openrewrite.java.Assertions.java; -import static org.openrewrite.java.Assertions.version; +import static org.openrewrite.java.Assertions.*; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test;