diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..7b016a89fb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.compile.nullAnalysis.mode": "automatic" +} \ No newline at end of file diff --git a/src/main/java/org/openrewrite/java/migrate/guava/AbstractNoGuavaImmutableCopyOf.java b/src/main/java/org/openrewrite/java/migrate/guava/AbstractNoGuavaImmutableCopyOf.java new file mode 100644 index 0000000000..243341254b --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/guava/AbstractNoGuavaImmutableCopyOf.java @@ -0,0 +1,144 @@ +/* + * Copyright 2023 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.guava; + +import org.jspecify.annotations.Nullable; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.JavaVisitor; +import org.openrewrite.java.MethodMatcher; +import org.openrewrite.java.search.UsesJavaVersion; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.tree.*; + +import java.time.Duration; + +abstract class AbstractNoGuavaImmutableCopyOf extends Recipe { + + private final String guavaType; + private final String javaType; + + AbstractNoGuavaImmutableCopyOf(String guavaType, String javaType) { + this.guavaType = guavaType; + this.javaType = javaType; + } + + private String getShortType(String fullyQualifiedType) { + return fullyQualifiedType.substring(javaType.lastIndexOf(".") + 1); + } + + @Override + public String getDisplayName() { + return "Prefer `" + getShortType(javaType) + ".copyOf(..)` in Java 10 or higher"; + } + + @Override + public String getDescription() { + return "Replaces `" + getShortType(guavaType) + ".copyOf(..)` if the returned type is immediately down-cast."; + } + + @Override + public Duration getEstimatedEffortPerOccurrence() { + return Duration.ofMinutes(10); + } + + @Override + public TreeVisitor getVisitor() { + TreeVisitor check = Preconditions.and(new UsesJavaVersion<>(10), + new UsesType<>(guavaType, false)); + final MethodMatcher IMMUTABLE_MATCHER = new MethodMatcher(guavaType + " copyOf(..)"); + return Preconditions.check(check, new JavaVisitor() { + @Override + public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { + if (IMMUTABLE_MATCHER.matches(method) && isParentTypeDownCast(method)) { + maybeRemoveImport(guavaType); + maybeAddImport(javaType); + + J.MethodInvocation templated = JavaTemplate.builder(getShortType(javaType) + ".copyOf(#{any()})") + .imports(javaType) + .build() + .apply(getCursor(), + method.getCoordinates().replace(), + method.getArguments().get(0)); + return templated.getPadding().withArguments(method.getPadding().getArguments()); + } + return super.visitMethodInvocation(method, ctx); + } + + private boolean isParentTypeDownCast(MethodCall immutableMethod) { + J parent = getCursor().dropParentUntil(J.class::isInstance).getValue(); + boolean isParentTypeDownCast = false; + if (parent instanceof J.VariableDeclarations.NamedVariable) { + isParentTypeDownCast = isParentTypeMatched(((J.VariableDeclarations.NamedVariable) parent).getType()); + } else if (parent instanceof J.Assignment) { + J.Assignment a = (J.Assignment) parent; + if (a.getVariable() instanceof J.Identifier && ((J.Identifier) a.getVariable()).getFieldType() != null) { + isParentTypeDownCast = isParentTypeMatched(((J.Identifier) a.getVariable()).getFieldType().getType()); + } else if (a.getVariable() instanceof J.FieldAccess) { + isParentTypeDownCast = isParentTypeMatched(a.getVariable().getType()); + } + } else if (parent instanceof J.Return) { + // Does not currently support returns in lambda expressions. + J j = getCursor().dropParentUntil(is -> is instanceof J.MethodDeclaration || is instanceof J.CompilationUnit).getValue(); + if (j instanceof J.MethodDeclaration) { + TypeTree returnType = ((J.MethodDeclaration) j).getReturnTypeExpression(); + if (returnType != null) { + isParentTypeDownCast = isParentTypeMatched(returnType.getType()); + } + } + } else if (parent instanceof J.MethodInvocation) { + J.MethodInvocation m = (J.MethodInvocation) parent; + int index = m.getArguments().indexOf(immutableMethod); + if (m.getMethodType() != null && index != -1) { + isParentTypeDownCast = isParentTypeMatched(m.getMethodType().getParameterTypes().get(index)); + } + } else if (parent instanceof J.NewClass) { + J.NewClass c = (J.NewClass) parent; + int index = 0; + if (c.getConstructorType() != null) { + for (Expression argument : c.getArguments()) { + if (IMMUTABLE_MATCHER.matches(argument)) { + break; + } + index++; + } + if (c.getConstructorType() != null) { + isParentTypeDownCast = isParentTypeMatched(c.getConstructorType().getParameterTypes().get(index)); + } + } + } else if (parent instanceof J.NewArray) { + J.NewArray a = (J.NewArray) parent; + JavaType arrayType = a.getType(); + while (arrayType instanceof JavaType.Array) { + arrayType = ((JavaType.Array) arrayType).getElemType(); + } + + isParentTypeDownCast = isParentTypeMatched(arrayType); + } + return isParentTypeDownCast; + } + + private boolean isParentTypeMatched(@Nullable JavaType type) { + JavaType.FullyQualified fq = TypeUtils.asFullyQualified(type); + return TypeUtils.isOfClassType(fq, javaType) || + TypeUtils.isOfClassType(fq, "java.lang.Object"); + } + }); + } +} diff --git a/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableListCopyOf.java b/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableListCopyOf.java new file mode 100644 index 0000000000..42ad4026f5 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableListCopyOf.java @@ -0,0 +1,22 @@ +/* + * Copyright 2023 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.guava; + +public class NoGuavaImmutableListCopyOf extends AbstractNoGuavaImmutableCopyOf { + public NoGuavaImmutableListCopyOf() { + super("com.google.common.collect.ImmutableList", "java.util.List"); + } +} diff --git a/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableMapCopyOf.java b/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableMapCopyOf.java new file mode 100644 index 0000000000..1d4e3d1aa3 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableMapCopyOf.java @@ -0,0 +1,22 @@ +/* + * Copyright 2023 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.guava; + +public class NoGuavaImmutableMapCopyOf extends AbstractNoGuavaImmutableCopyOf { + public NoGuavaImmutableMapCopyOf() { + super("com.google.common.collect.ImmutableMap", "java.util.Map"); + } +} diff --git a/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableSetCopyOf.java b/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableSetCopyOf.java new file mode 100644 index 0000000000..fb26645a78 --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableSetCopyOf.java @@ -0,0 +1,22 @@ +/* + * Copyright 2023 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.guava; + +public class NoGuavaImmutableSetCopyOf extends AbstractNoGuavaImmutableCopyOf { + public NoGuavaImmutableSetCopyOf() { + super("com.google.common.collect.ImmutableSet", "java.util.Set"); + } +} diff --git a/src/main/resources/META-INF/rewrite/no-guava.yml b/src/main/resources/META-INF/rewrite/no-guava.yml index 9db88a136f..82c1291510 100644 --- a/src/main/resources/META-INF/rewrite/no-guava.yml +++ b/src/main/resources/META-INF/rewrite/no-guava.yml @@ -77,6 +77,9 @@ recipeList: - org.openrewrite.java.migrate.guava.NoGuavaImmutableListOf - org.openrewrite.java.migrate.guava.NoGuavaImmutableMapOf - org.openrewrite.java.migrate.guava.NoGuavaImmutableSetOf + - org.openrewrite.java.migrate.guava.NoGuavaImmutableSetCopyOf + - org.openrewrite.java.migrate.guava.NoGuavaImmutableListCopyOf + - org.openrewrite.java.migrate.guava.NoGuavaImmutableMapCopyOf - org.openrewrite.java.migrate.guava.PreferJavaUtilObjectsRequireNonNullElse - org.openrewrite.java.dependencies.UpgradeDependencyVersion: groupId: io.springfox diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableListCopyOfTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableListCopyOfTest.java new file mode 100644 index 0000000000..3114d85748 --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableListCopyOfTest.java @@ -0,0 +1,481 @@ +/* + * Copyright 2023 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.guava; + +import org.junit.jupiter.api.Test; +import org.openrewrite.java.JavaParser; +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 NoGuavaImmutableListCopyOfTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .recipe(new NoGuavaImmutableListCopyOf()) + .parser(JavaParser.fromJavaVersion().classpath("guava")); + } + + @Test + void doNotChangeReturnsImmutableList() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableList; + + class Test { + ImmutableList getList() { + return ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeFieldAssignmentToImmutableList() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableList; + + class Test { + ImmutableList m; + + { + this.m = ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeAssignsToImmutableList() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableList; + + class Test { + ImmutableList m; + + void init() { + m = ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeNewClass() { + rewriteRun( + spec -> spec.parser( + JavaParser.fromJavaVersion() + .classpath("guava") + .dependsOn( + //language=java + """ + import com.google.common.collect.ImmutableList; + + public class A { + ImmutableList immutableList; + public A(ImmutableList immutableList) { + this.immutableList = immutableList; + } + } + """ + ) + ), + java( + """ + import com.google.common.collect.ImmutableList; + + class Test { + A a = new A(ImmutableList.copyOf(new String[]{"A", "B", "C"})); + } + """ + ) + ); + } + + @Test + void doNotChangeMethodInvocation() { + rewriteRun( + spec -> spec.parser( + JavaParser.fromJavaVersion() + .classpath("guava") + .dependsOn( + //language=java + """ + import com.google.common.collect.ImmutableList; + + public class A { + ImmutableList immutableList; + public void method(ImmutableList immutableList) { + this.immutableList = immutableList; + } + } + """ + ) + ), + java( + """ + import com.google.common.collect.ImmutableList; + + class Test { + void method() { + A a = new A(); + a.method(ImmutableList.copyOf(new String[]{"A", "B", "C"})); + } + } + """ + ) + ); + } + + @Test + void replaceArguments() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.List; + import com.google.common.collect.ImmutableList; + + class Test { + List m = ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.List; + + class Test { + List m = List.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void fieldAssignmentToList() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.List; + import com.google.common.collect.ImmutableList; + + class Test { + List m; + { + this.m = ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + } + """, + """ + import java.util.List; + + class Test { + List m; + { + this.m = List.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void assignmentToList() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.List; + import com.google.common.collect.ImmutableList; + + class Test { + List m = ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.List; + + class Test { + List m = List.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void returnsList() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.List; + import com.google.common.collect.ImmutableList; + + class Test { + List list() { + return ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + } + """, + """ + import java.util.List; + + class Test { + List list() { + return List.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void newClassWithListArgument() { + //language=java + rewriteRun( + java( + """ + import java.util.List; + + public class A { + List list; + public A(List list) { + this.list = list; + } + } + """ + ), + version( + //language=java + java( + """ + import com.google.common.collect.ImmutableList; + + class Test { + A a = new A(ImmutableList.copyOf(new String[]{"A", "B", "C"})); + } + """, + """ + import java.util.List; + + class Test { + A a = new A(List.copyOf(new String[]{"A", "B", "C"})); + } + """ + ), + 10 + ) + ); + } + + @Test + void methodInvocationWithListArgument() { + //language=java + rewriteRun( + java( + """ + import java.util.List; + + public class A { + List list; + public void method(List list) { + this.list = list; + } + } + """ + ), + version( + java( + """ + import com.google.common.collect.ImmutableList; + + class Test { + void method() { + A a = new A(); + a.method(ImmutableList.copyOf(new String[]{"A", "B", "C"})); + } + } + """, + """ + import java.util.List; + + class Test { + void method() { + A a = new A(); + a.method(List.copyOf(new String[]{"A", "B", "C"})); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void insideAnonymousArrayInitializer() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableList; + + class A { + Object[] o = new Object[] { + ImmutableList.copyOf(new String[]{"A", "B", "C"}) + }; + } + """, + """ + import java.util.List; + + class A { + Object[] o = new Object[] { + List.copyOf(new String[]{"A", "B", "C"}) + }; + } + """ + ), + 10 + ) + ); + } + + @Test + void assignToMoreGeneralType() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableList; + + class A { + Object o = ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.List; + + class A { + Object o = List.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void doNotChangeNestedLists() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableList; + import java.util.List; + + class A { + Object o = List.copyOf(ImmutableList.copyOf(new String[]{"A", "B", "C"})); + } + """ + ), + 10 + ) + ); + } + + @Test + void doNotChangeAssignToImmutableList() { + //language=java + rewriteRun( + spec -> spec.allSources(all -> all.markers(javaVersion(10))), + java( + """ + import com.google.common.collect.ImmutableList; + + class Test { + ImmutableList m = ImmutableList.copyOf(new String[]{"A", "B", "C"}); + } + """ + ) + ); + } + + @Test + void multiLine() { + //language=java + rewriteRun( + spec -> spec.allSources(all -> all.markers(javaVersion(10))), + java( + """ + import com.google.common.collect.ImmutableList; + import java.util.List; + + class Test { + List m = ImmutableList.copyOf( + new String[]{"A", "B", "C"} + ); + } + """, + """ + import java.util.List; + + class Test { + List m = List.copyOf( + new String[]{"A", "B", "C"} + ); + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableMapCopyOfTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableMapCopyOfTest.java new file mode 100644 index 0000000000..ffcae248f8 --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableMapCopyOfTest.java @@ -0,0 +1,482 @@ +/* + * Copyright 2023 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.guava; + +import org.junit.jupiter.api.Test; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.Assertions.javaVersion; +import static org.openrewrite.java.Assertions.version; + +class NoGuavaImmutableMapCopyOfTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .recipe(new NoGuavaImmutableMapCopyOf()) + .parser(JavaParser.fromJavaVersion().classpath("guava")); + } + + @Test + void doNotChangeReturnsImmutableMap() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableMap; + + class Test { + ImmutableMap getMap() { + return ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeFieldAssignmentToImmutableMap() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableMap; + + class Test { + ImmutableMap m; + + { + this.m = ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeAssignsToImmutableMap() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableMap; + + class Test { + ImmutableMap m; + + void init() { + m = ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeNewClass() { + rewriteRun( + spec -> spec.parser( + JavaParser.fromJavaVersion() + .classpath("guava") + .dependsOn( + //language=java + """ + import com.google.common.collect.ImmutableMap; + + public class A { + ImmutableMap immutableMap; + public A(ImmutableMap immutableMap) { + this.immutableMap = immutableMap; + } + } + """ + ) + ), + java( + """ + import com.google.common.collect.ImmutableMap; + + class Test { + A a = new A(ImmutableMap.copyOf(new String[]{"A", "B", "C"})); + } + """ + ) + ); + } + + @Test + void doNotChangeMethodInvocation() { + rewriteRun( + spec -> spec.parser( + JavaParser.fromJavaVersion() + .classpath("guava") + .dependsOn( + //language=java + """ + import com.google.common.collect.ImmutableMap; + + public class A { + ImmutableMap immutableMap; + public void method(ImmutableMap immutableMap) { + this.immutableMap = immutableMap; + } + } + """ + ) + ), + java( + """ + import com.google.common.collect.ImmutableMap; + + class Test { + void method() { + A a = new A(); + a.method(ImmutableMap.copyOf(new String[]{"A", "B", "C"})); + } + } + """ + ) + ); + } + + @Test + void replaceArguments() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.Map; + import com.google.common.collect.ImmutableMap; + + class Test { + Map m = ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.Map; + + class Test { + Map m = Map.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void fieldAssignmentToMap() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.Map; + import com.google.common.collect.ImmutableMap; + + class Test { + Map m; + { + this.m = ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + } + """, + """ + import java.util.Map; + + class Test { + Map m; + { + this.m = Map.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void assignmentToMap() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.Map; + import com.google.common.collect.ImmutableMap; + + class Test { + Map m = ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.Map; + + class Test { + Map m = Map.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void returnsMap() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.Map; + import com.google.common.collect.ImmutableMap; + + class Test { + Map map() { + return ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + } + """, + """ + import java.util.Map; + + class Test { + Map map() { + return Map.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void newClassWithMapArgument() { + //language=java + rewriteRun( + java( + """ + import java.util.Map; + + public class A { + Map map; + public A(Map map) { + this.map = map; + } + } + """ + ), + version( + //language=java + java( + """ + import com.google.common.collect.ImmutableMap; + + class Test { + A a = new A(ImmutableMap.copyOf(new String[]{"A", "B", "C"})); + } + """, + """ + import java.util.Map; + + class Test { + A a = new A(Map.copyOf(new String[]{"A", "B", "C"})); + } + """ + ), + 10 + ) + ); + } + + @Test + void methodInvocationWithMapArgument() { + //language=java + rewriteRun( + java( + """ + import java.util.Map; + + public class A { + Map map; + public void method(Map map) { + this.map = map; + } + } + """ + ), + version( + java( + """ + import com.google.common.collect.ImmutableMap; + + class Test { + void method() { + A a = new A(); + a.method(ImmutableMap.copyOf(new String[]{"A", "B", "C"})); + } + } + """, + """ + import java.util.Map; + + class Test { + void method() { + A a = new A(); + a.method(Map.copyOf(new String[]{"A", "B", "C"})); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void insideAnonymousArrayInitializer() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableMap; + + class A { + Object[] o = new Object[] { + ImmutableMap.copyOf(new String[]{"A", "B", "C"}) + }; + } + """, + """ + import java.util.Map; + + class A { + Object[] o = new Object[] { + Map.copyOf(new String[]{"A", "B", "C"}) + }; + } + """ + ), + 10 + ) + ); + } + + @Test + void assignToMoreGeneralType() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableMap; + + class A { + Object o = ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.Map; + + class A { + Object o = Map.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void doNotChangeNestedMaps() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableMap; + import java.util.Map; + + class A { + Object o = Map.copyOf(ImmutableMap.copyOf(new String[]{"A", "B", "C"})); + } + """ + ), + 10 + ) + ); + } + + @Test + void doNotChangeAssignToImmutableMap() { + //language=java + rewriteRun( + spec -> spec.allSources(all -> all.markers(javaVersion(10))), + java( + """ + import com.google.common.collect.ImmutableMap; + + class Test { + ImmutableMap m = ImmutableMap.copyOf(new String[]{"A", "B", "C"}); + } + """ + ) + ); + } + + @Test + void multiLine() { + //language=java + rewriteRun( + spec -> spec.allSources(all -> all.markers(javaVersion(10))), + java( + """ + import com.google.common.collect.ImmutableMap; + import java.util.Map; + + class Test { + Map m = ImmutableMap.copyOf( + new String[]{"A", "B", "C"} + ); + } + """, + """ + import java.util.Map; + + class Test { + Map m = Map.copyOf( + new String[]{"A", "B", "C"} + ); + } + """ + ) + ); + } +} diff --git a/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableSetCopyOfTest.java b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableSetCopyOfTest.java new file mode 100644 index 0000000000..4669a863a4 --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/guava/NoGuavaImmutableSetCopyOfTest.java @@ -0,0 +1,482 @@ +/* + * Copyright 2023 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.guava; + +import org.junit.jupiter.api.Test; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; +import static org.openrewrite.java.Assertions.javaVersion; +import static org.openrewrite.java.Assertions.version; + +class NoGuavaImmutableSetCopyOfTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec + .recipe(new NoGuavaImmutableSetCopyOf()) + .parser(JavaParser.fromJavaVersion().classpath("guava")); + } + + @Test + void doNotChangeReturnsImmutableSet() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableSet; + + class Test { + ImmutableSet getSet() { + return ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeFieldAssignmentToImmutableSet() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableSet; + + class Test { + ImmutableSet m; + + { + this.m = ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeAssignsToImmutableSet() { + //language=java + rewriteRun( + java( + """ + import com.google.common.collect.ImmutableSet; + + class Test { + ImmutableSet m; + + void init() { + m = ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ) + ); + } + + @Test + void doNotChangeNewClass() { + rewriteRun( + spec -> spec.parser( + JavaParser.fromJavaVersion() + .classpath("guava") + .dependsOn( + //language=java + """ + import com.google.common.collect.ImmutableSet; + + public class A { + ImmutableSet immutableSet; + public A(ImmutableSet immutableSet) { + this.immutableSet = immutableSet; + } + } + """ + ) + ), + java( + """ + import com.google.common.collect.ImmutableSet; + + class Test { + A a = new A(ImmutableSet.copyOf(new String[]{"A", "B", "C"})); + } + """ + ) + ); + } + + @Test + void doNotChangeMethodInvocation() { + rewriteRun( + spec -> spec.parser( + JavaParser.fromJavaVersion() + .classpath("guava") + .dependsOn( + //language=java + """ + import com.google.common.collect.ImmutableSet; + + public class A { + ImmutableSet immutableSet; + public void method(ImmutableSet immutableSet) { + this.immutableSet = immutableSet; + } + } + """ + ) + ), + java( + """ + import com.google.common.collect.ImmutableSet; + + class Test { + void method() { + A a = new A(); + a.method(ImmutableSet.copyOf(new String[]{"A", "B", "C"})); + } + } + """ + ) + ); + } + + @Test + void replaceArguments() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.Set; + import com.google.common.collect.ImmutableSet; + + class Test { + Set m = ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.Set; + + class Test { + Set m = Set.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void fieldAssignmentToSet() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.Set; + import com.google.common.collect.ImmutableSet; + + class Test { + Set m; + { + this.m = ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + } + """, + """ + import java.util.Set; + + class Test { + Set m; + { + this.m = Set.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void assignmentToSet() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.Set; + import com.google.common.collect.ImmutableSet; + + class Test { + Set m = ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.Set; + + class Test { + Set m = Set.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void returnsSet() { + //language=java + rewriteRun( + version( + java( + """ + import java.util.Set; + import com.google.common.collect.ImmutableSet; + + class Test { + Set set() { + return ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + } + """, + """ + import java.util.Set; + + class Test { + Set set() { + return Set.copyOf(new String[]{"A", "B", "C"}); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void newClassWithSetArgument() { + //language=java + rewriteRun( + java( + """ + import java.util.Set; + + public class A { + Set set; + public A(Set set) { + this.set = set; + } + } + """ + ), + version( + //language=java + java( + """ + import com.google.common.collect.ImmutableSet; + + class Test { + A a = new A(ImmutableSet.copyOf(new String[]{"A", "B", "C"})); + } + """, + """ + import java.util.Set; + + class Test { + A a = new A(Set.copyOf(new String[]{"A", "B", "C"})); + } + """ + ), + 10 + ) + ); + } + + @Test + void methodInvocationWithSetArgument() { + //language=java + rewriteRun( + java( + """ + import java.util.Set; + + public class A { + Set set; + public void method(Set set) { + this.set = set; + } + } + """ + ), + version( + java( + """ + import com.google.common.collect.ImmutableSet; + + class Test { + void method() { + A a = new A(); + a.method(ImmutableSet.copyOf(new String[]{"A", "B", "C"})); + } + } + """, + """ + import java.util.Set; + + class Test { + void method() { + A a = new A(); + a.method(Set.copyOf(new String[]{"A", "B", "C"})); + } + } + """ + ), + 10 + ) + ); + } + + @Test + void insideAnonymousArrayInitializer() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableSet; + + class A { + Object[] o = new Object[] { + ImmutableSet.copyOf(new String[]{"A", "B", "C"}) + }; + } + """, + """ + import java.util.Set; + + class A { + Object[] o = new Object[] { + Set.copyOf(new String[]{"A", "B", "C"}) + }; + } + """ + ), + 10 + ) + ); + } + + @Test + void assignToMoreGeneralType() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableSet; + + class A { + Object o = ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + """, + """ + import java.util.Set; + + class A { + Object o = Set.copyOf(new String[]{"A", "B", "C"}); + } + """ + ), + 10 + ) + ); + } + + @Test + void doNotChangeNestedSets() { + //language=java + rewriteRun( + version( + java( + """ + import com.google.common.collect.ImmutableSet; + import java.util.Set; + + class A { + Object o = Set.copyOf(ImmutableSet.copyOf(new String[]{"A", "B", "C"})); + } + """ + ), + 10 + ) + ); + } + + @Test + void doNotChangeAssignToImmutableSet() { + //language=java + rewriteRun( + spec -> spec.allSources(all -> all.markers(javaVersion(10))), + java( + """ + import com.google.common.collect.ImmutableSet; + + class Test { + ImmutableSet m = ImmutableSet.copyOf(new String[]{"A", "B", "C"}); + } + """ + ) + ); + } + + @Test + void multiLine() { + //language=java + rewriteRun( + spec -> spec.allSources(all -> all.markers(javaVersion(10))), + java( + """ + import com.google.common.collect.ImmutableSet; + import java.util.Set; + + class Test { + Set m = ImmutableSet.copyOf( + new String[]{"A", "B", "C"} + ); + } + """, + """ + import java.util.Set; + + class Test { + Set m = Set.copyOf( + new String[]{"A", "B", "C"} + ); + } + """ + ) + ); + } +}