Skip to content

Commit 9c99820

Browse files
ranuradhAnuRam123github-actions[bot]timtebeek
authored
Replace Reference.clone() with new constructor in Java 11 migration (#510)
* Java 11 recipe remove ReferenceCloneMethod * udpated test * Update src/test/java/org/openrewrite/java/migrate/ReferenceCloneMethodTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Update src/test/java/org/openrewrite/java/migrate/ReferenceCloneMethodTest.java Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Polish whitespace in text blocks * Clean up unnecessary type casts * Shorten all fully qualified types on replacement constructor --------- Co-authored-by: anuram <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Tim te Beek <[email protected]>
1 parent ceecc08 commit 9c99820

File tree

3 files changed

+184
-2
lines changed

3 files changed

+184
-2
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.migrate;
17+
18+
import lombok.EqualsAndHashCode;
19+
import lombok.Value;
20+
import org.openrewrite.ExecutionContext;
21+
import org.openrewrite.Preconditions;
22+
import org.openrewrite.Recipe;
23+
import org.openrewrite.TreeVisitor;
24+
import org.openrewrite.java.JavaTemplate;
25+
import org.openrewrite.java.JavaVisitor;
26+
import org.openrewrite.java.MethodMatcher;
27+
import org.openrewrite.java.ShortenFullyQualifiedTypeReferences;
28+
import org.openrewrite.java.search.UsesMethod;
29+
import org.openrewrite.java.tree.J;
30+
import org.openrewrite.java.tree.TypeUtils;
31+
32+
33+
@Value
34+
@EqualsAndHashCode(callSuper = false)
35+
class ReferenceCloneMethod extends Recipe {
36+
private static final MethodMatcher REFERENCE_CLONE = new MethodMatcher("java.lang.ref.Reference clone()", true);
37+
38+
@Override
39+
public String getDisplayName() {
40+
return "Replace `java.lang.ref.Reference.clone()` with constructor call";
41+
}
42+
43+
@Override
44+
public String getDescription() {
45+
return "The recipe replaces any clone calls that may resolve to a `java.lang.ref.Reference.clone()` " +
46+
"or any of its known subclasses: `java.lang.ref.PhantomReference`, `java.lang.ref.SoftReference`, and `java.lang.ref.WeakReference` " +
47+
"with a constructor call passing in the referent and reference queue as parameters.";
48+
}
49+
50+
@Override
51+
public TreeVisitor<?, ExecutionContext> getVisitor() {
52+
return Preconditions.check(
53+
new UsesMethod<>(REFERENCE_CLONE),
54+
new JavaVisitor<ExecutionContext>() {
55+
private static final String REFERENCE_CLONE_REPLACED = "REFERENCE_CLONE_REPLACED";
56+
57+
@Override
58+
public J visitTypeCast(J.TypeCast typeCast, ExecutionContext ctx) {
59+
J j = super.visitTypeCast(typeCast, ctx);
60+
if (Boolean.TRUE.equals(getCursor().pollNearestMessage(REFERENCE_CLONE_REPLACED))
61+
&& j instanceof J.TypeCast) {
62+
J.TypeCast tc = (J.TypeCast) j;
63+
if (TypeUtils.isOfType(tc.getType(), tc.getExpression().getType())) {
64+
return tc.getExpression();
65+
}
66+
}
67+
return j;
68+
}
69+
70+
@Override
71+
public J visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
72+
super.visitMethodInvocation(method, ctx);
73+
if (REFERENCE_CLONE.matches(method) && method.getSelect() instanceof J.Identifier) {
74+
J.Identifier methodRef = (J.Identifier) method.getSelect();
75+
String template = "new " + methodRef.getType().toString() + "(" + methodRef.getSimpleName() + ", new ReferenceQueue<>())";
76+
getCursor().putMessageOnFirstEnclosing(J.TypeCast.class, REFERENCE_CLONE_REPLACED, true);
77+
J replacement = JavaTemplate.builder(template)
78+
.contextSensitive()
79+
.imports("java.lang.ref.ReferenceQueue")
80+
.build().apply(getCursor(), method.getCoordinates().replace());
81+
doAfterVisit(ShortenFullyQualifiedTypeReferences.modifyOnly(replacement));
82+
return replacement;
83+
}
84+
return method;
85+
}
86+
}
87+
);
88+
}
89+
}

src/main/resources/META-INF/rewrite/java-version-11.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ recipeList:
6767
- org.openrewrite.java.migrate.RemovedSecurityManagerMethods
6868
- org.openrewrite.java.migrate.UpgradePluginsForJava11
6969
- org.openrewrite.java.migrate.RemovedPolicy
70+
- org.openrewrite.java.migrate.ReferenceCloneMethod
7071
- org.openrewrite.java.migrate.ThreadStopDestroy
71-
7272
---
7373
type: specs.openrewrite.org/v1beta/recipe
7474
name: org.openrewrite.java.migrate.UpgradeBuildToJava11
@@ -263,4 +263,4 @@ recipeList:
263263
- org.openrewrite.java.migrate.RemoveMethodInvocation:
264264
methodPattern: java.lang.Thread destroy()
265265
- org.openrewrite.java.migrate.RemoveMethodInvocation:
266-
methodPattern: java.lang.Thread stop(java.lang.Throwable)
266+
methodPattern: java.lang.Thread stop(java.lang.Throwable)
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.openrewrite.java.migrate;
17+
18+
import org.junit.jupiter.api.Test;
19+
import org.openrewrite.DocumentExample;
20+
import org.openrewrite.test.RecipeSpec;
21+
import org.openrewrite.test.RewriteTest;
22+
23+
import static org.openrewrite.java.Assertions.java;
24+
25+
class ReferenceCloneMethodTest implements RewriteTest {
26+
27+
@Override
28+
public void defaults(RecipeSpec spec) {
29+
spec.recipe(new ReferenceCloneMethod());
30+
}
31+
32+
@DocumentExample
33+
@Test
34+
void referenceCloneRemoval() {
35+
rewriteRun(
36+
//language=java
37+
java(
38+
"""
39+
import java.lang.ref.WeakReference;
40+
import java.lang.ref.SoftReference;
41+
import java.lang.ref.PhantomReference;
42+
43+
class Foo {
44+
void foo() throws Exception{
45+
WeakReference<Object> ref = new WeakReference<Object>(null);
46+
WeakReference<Object> ref1 = (WeakReference<Object>) ref.clone();
47+
SoftReference<Object> ref3 = new SoftReference<Object>(null);
48+
SoftReference<Object> ref4 = (SoftReference<Object>) ref3.clone();
49+
PhantomReference<Object> ref5 = new PhantomReference<Object>(null,null);
50+
PhantomReference<Object> ref6 = (PhantomReference<Object>) ref5.clone();
51+
}
52+
}
53+
""",
54+
"""
55+
import java.lang.ref.WeakReference;
56+
import java.lang.ref.SoftReference;
57+
import java.lang.ref.PhantomReference;
58+
59+
class Foo {
60+
void foo() throws Exception{
61+
WeakReference<Object> ref = new WeakReference<Object>(null);
62+
WeakReference<Object> ref1 = new WeakReference<Object>(ref, new ReferenceQueue<>());
63+
SoftReference<Object> ref3 = new SoftReference<Object>(null);
64+
SoftReference<Object> ref4 = new SoftReference<Object>(ref3, new ReferenceQueue<>());
65+
PhantomReference<Object> ref5 = new PhantomReference<Object>(null,null);
66+
PhantomReference<Object> ref6 = new PhantomReference<Object>(ref5, new ReferenceQueue<>());
67+
}
68+
}
69+
"""
70+
)
71+
);
72+
}
73+
74+
@Test
75+
void noCloneRemoval() {
76+
rewriteRun(
77+
//language=java
78+
java(
79+
"""
80+
class ClonableClass implements Cloneable {
81+
public ClonableClass(int id) {
82+
}
83+
84+
@Override
85+
public Object clone() throws CloneNotSupportedException {
86+
return super.clone();
87+
}
88+
}
89+
"""
90+
)
91+
);
92+
}
93+
}

0 commit comments

Comments
 (0)