diff --git a/src/main/java/org/openrewrite/java/migrate/ReferenceCloneMethod.java b/src/main/java/org/openrewrite/java/migrate/ReferenceCloneMethod.java index b033ecef81..f518243f42 100644 --- a/src/main/java/org/openrewrite/java/migrate/ReferenceCloneMethod.java +++ b/src/main/java/org/openrewrite/java/migrate/ReferenceCloneMethod.java @@ -17,12 +17,16 @@ import lombok.EqualsAndHashCode; import lombok.Value; -import org.openrewrite.*; +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.UsesMethod; -import org.openrewrite.java.tree.*; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.TypeUtils; @Value @@ -32,34 +36,53 @@ class ReferenceCloneMethod extends Recipe { @Override public String getDisplayName() { - return "Remove the use of `java.lang.ref.Reference.clone()` method"; + return "Replace `java.lang.ref.Reference.clone()` with constructor call"; } @Override public String getDescription() { return "The recipe replaces any clone calls that may resolve to a `java.lang.ref.Reference.clone()` " + - "or any of its known subclasses: `java.lang.ref.PhantomReference`, `java.lang.ref.SoftReference`, and `java.lang.ref.WeakReference` " + - "with a constructor call passing in the referent and reference queue as parameters."; + "or any of its known subclasses: `java.lang.ref.PhantomReference`, `java.lang.ref.SoftReference`, and `java.lang.ref.WeakReference` " + + "with a constructor call passing in the referent and reference queue as parameters."; } @Override public TreeVisitor getVisitor() { - return Preconditions.check( new UsesMethod<>(REFERENCE_CLONE), new JavaVisitor() { + return Preconditions.check( + new UsesMethod<>(REFERENCE_CLONE), + new JavaVisitor() { + + private static final String REFERENCE_CLONE_REPLACED = "REFERENCE_CLONE_REPLACED"; + + @Override + public J visitTypeCast(J.TypeCast typeCast, ExecutionContext executionContext) { + J j = super.visitTypeCast(typeCast, executionContext); + if (Boolean.TRUE.equals(getCursor().pollNearestMessage(REFERENCE_CLONE_REPLACED)) + && j instanceof J.TypeCast) { + J.TypeCast tc = (J.TypeCast) j; + if (TypeUtils.isOfType(tc.getType(), tc.getExpression().getType())) { + return tc.getExpression(); + } + } + return j; + } + @Override public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) { super.visitMethodInvocation(method, ctx); - if (REFERENCE_CLONE.matches(method)) { - Expression methodRef = method.getSelect(); - assert method.getSelect() != null; - String argumentName = ((J.Identifier) method.getSelect()).getSimpleName(); - if(methodRef.getType().toString()!=null) { - String templateBuilder = "new " + methodRef.getType().toString() + "(" + argumentName + ", new ReferenceQueue<>())"; - JavaTemplate newReference = JavaTemplate.builder(templateBuilder) - .contextSensitive() - .imports("java.lang.ref.ReferenceQueue") - .build(); - return newReference.apply(getCursor(), method.getCoordinates().replace()); - } + if (REFERENCE_CLONE.matches(method) && method.getSelect() instanceof J.Identifier) { + J.Identifier methodRef = (J.Identifier) method.getSelect(); + String className = methodRef.getType().toString() + .replace("java.lang.ref.", "") + .replace("java.lang.", ""); + String template = "new " + className + "(" + methodRef.getSimpleName() + ", new ReferenceQueue<>())"; + getCursor().putMessageOnFirstEnclosing(J.TypeCast.class, REFERENCE_CLONE_REPLACED, true); + return JavaTemplate.builder(template) + .contextSensitive() + .imports( + methodRef.getType().toString(), + "java.lang.ref.ReferenceQueue") + .build().apply(getCursor(), method.getCoordinates().replace()); } return method; } diff --git a/src/test/java/org/openrewrite/java/migrate/ReferenceCloneMethodTest.java b/src/test/java/org/openrewrite/java/migrate/ReferenceCloneMethodTest.java index 51e6058f9d..0514c013f3 100644 --- a/src/test/java/org/openrewrite/java/migrate/ReferenceCloneMethodTest.java +++ b/src/test/java/org/openrewrite/java/migrate/ReferenceCloneMethodTest.java @@ -26,13 +26,13 @@ class ReferenceCloneMethodTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { + spec.recipe(new ReferenceCloneMethod()); } @DocumentExample @Test void referenceCloneRemoval() { rewriteRun( - spec -> spec.recipe(new ReferenceCloneMethod()), //language=java java( """ @@ -59,11 +59,11 @@ void foo() throws Exception{ class Foo { void foo() throws Exception{ WeakReference ref = new WeakReference(null); - WeakReference ref1 = (WeakReference) new java.lang.ref.WeakReference(ref, new ReferenceQueue<>()); + WeakReference ref1 = new WeakReference(ref, new ReferenceQueue<>()); SoftReference ref3 = new SoftReference(null); - SoftReference ref4 = (SoftReference) new java.lang.ref.SoftReference(ref3, new ReferenceQueue<>()); + SoftReference ref4 = new SoftReference(ref3, new ReferenceQueue<>()); PhantomReference ref5 = new PhantomReference(null,null); - PhantomReference ref6 = (PhantomReference) new java.lang.ref.PhantomReference(ref5, new ReferenceQueue<>()); + PhantomReference ref6 = new PhantomReference(ref5, new ReferenceQueue<>()); } } """ @@ -74,7 +74,6 @@ void foo() throws Exception{ @Test void noCloneRemoval() { rewriteRun( - spec -> spec.recipe(new ReferenceCloneMethod()), //language=java java( """