Skip to content

Commit 81341a8

Browse files
committed
ReplaceClassIsInstanceWithInstanceof: Fix another corner case
1 parent 2ed0ae0 commit 81341a8

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

src/main/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceof.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,28 @@
1717

1818
import org.jspecify.annotations.Nullable;
1919
import org.openrewrite.ExecutionContext;
20+
import org.openrewrite.Preconditions;
2021
import org.openrewrite.Recipe;
22+
import org.openrewrite.TreeVisitor;
2123
import org.openrewrite.java.JavaTemplate;
2224
import org.openrewrite.java.JavaVisitor;
2325
import org.openrewrite.java.MethodMatcher;
24-
import org.openrewrite.java.tree.*;
26+
import org.openrewrite.java.search.UsesMethod;
27+
import org.openrewrite.java.tree.Expression;
28+
import org.openrewrite.java.tree.J;
2529
import org.openrewrite.java.tree.J.FieldAccess;
2630
import org.openrewrite.java.tree.J.Identifier;
2731
import org.openrewrite.java.tree.J.MethodInvocation;
32+
import org.openrewrite.java.tree.JavaCoordinates;
33+
import org.openrewrite.java.tree.JavaType;
2834

2935
import java.util.Collections;
3036
import java.util.Set;
3137

3238
public class ReplaceClassIsInstanceWithInstanceof extends Recipe {
3339

40+
private static final MethodMatcher ISINSTANCE_MATCHER = new MethodMatcher("java.lang.Class isInstance(..)");
41+
3442
@Override
3543
public String getDisplayName() {
3644
return "Replace `A.class.isInstance(a)` with `a instanceof A`";
@@ -47,25 +55,22 @@ public Set<String> getTags() {
4755
}
4856

4957
@Override
50-
public JavaVisitor<ExecutionContext> getVisitor() {
58+
public TreeVisitor<?, ExecutionContext> getVisitor() {
5159
// use JavaVisitor instead of JavaIsoVisitor because we changed the type of LST
52-
return new JavaVisitor<ExecutionContext>() {
53-
54-
private final MethodMatcher matcher = new MethodMatcher("java.lang.Class isInstance(java.lang.Object)");
60+
return Preconditions.check(new UsesMethod<>(ISINSTANCE_MATCHER), new JavaVisitor<ExecutionContext>() {
5561

5662
@Override
5763
public J visitMethodInvocation(MethodInvocation method, ExecutionContext ctx) {
5864
// make sure we find the right method and the left part is something like "SomeClass.class"
59-
if (matcher.matches(method) && isObjectClass(method.getSelect())) {
65+
if (ISINSTANCE_MATCHER.matches(method) && isObjectClass(method.getSelect())) {
6066
// for code like "A.class.isInstance(a)", select is "String.class", name is "isInstance", argument is "a"
6167
Expression objectExpression = method.getArguments().get(0);
6268
FieldAccess fieldAccessPart = (FieldAccess) method.getSelect();
63-
String className = fieldAccessPart.getTarget().toString();
6469
// upcast to type J, so J.MethodInvocation can be replaced by J.InstanceOf
6570
JavaCoordinates coordinates = method.getCoordinates().replace();
66-
J.InstanceOf instanceOf = JavaTemplate.builder("#{any()} instanceof #{}")
71+
J.InstanceOf instanceOf = JavaTemplate.builder("#{any()} instanceof Object")
6772
.build()
68-
.apply(getCursor(), coordinates, new Object[]{objectExpression, className});
73+
.apply(getCursor(), coordinates, objectExpression);
6974
instanceOf = instanceOf.withClazz(fieldAccessPart.getTarget().withPrefix(instanceOf.getClazz().getPrefix()));
7075
return maybeAutoFormat(method, instanceOf, ctx);
7176
}
@@ -75,13 +80,13 @@ public J visitMethodInvocation(MethodInvocation method, ExecutionContext ctx) {
7580
private boolean isObjectClass(@Nullable Expression expression) {
7681
if (expression instanceof J.FieldAccess) {
7782
J.FieldAccess fieldAccess = (J.FieldAccess) expression;
78-
if (fieldAccess.getTarget() instanceof Identifier) {
83+
if (fieldAccess.getName().getSimpleName().equals("class") && fieldAccess.getTarget() instanceof Identifier) {
7984
Identifier identifier = (Identifier) fieldAccess.getTarget();
8085
return identifier.getType() instanceof JavaType.Class;
8186
}
8287
}
8388
return false;
8489
}
85-
};
90+
});
8691
}
8792
}

src/test/java/org/openrewrite/staticanalysis/ReplaceClassIsInstanceWithInstanceofTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,4 +265,21 @@ boolean foo(Object obj) {
265265
);
266266
}
267267

268+
@Test
269+
void typeVariable() {
270+
rewriteRun(
271+
//language=java
272+
java(
273+
"""
274+
class A {
275+
Class<?> clazz;
276+
boolean foo(Object obj) {
277+
return this.clazz.isInstance(obj);
278+
}
279+
}
280+
"""
281+
)
282+
);
283+
}
284+
268285
}

0 commit comments

Comments
 (0)