Skip to content

Commit eb91699

Browse files
timtebeekclaude
andauthored
Fix ReplaceLambdaWithMethodReference handling of nested class imports (#745)
* Fix ReplaceLambdaWithMethodReference handling of nested class imports When transforming lambdas with instanceof checks or casts to method references, preserve the original form of the class reference instead of always generating a fully qualified name. This ensures that if a nested class like Map.Entry is already imported as `import java.util.Map.Entry`, the transformed code uses `Entry.class::isInstance` instead of `Map.Entry.class::isInstance`. The fix directly uses the original expression from the instanceof/cast rather than reconstructing it, allowing the ImportService to properly handle any necessary import adjustments while preserving the user's preferred form. Fixes #744 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Minimize diff --------- Co-authored-by: Claude <[email protected]>
1 parent a5d78d7 commit eb91699

File tree

3 files changed

+105
-18
lines changed

3 files changed

+105
-18
lines changed

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

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,18 +120,13 @@ static J.MemberReference newInstanceMethodReference(Expression containing, Strin
120120
);
121121
}
122122

123-
static J.@Nullable FieldAccess newClassLiteral(@Nullable JavaType type, boolean qualified) {
124-
JavaType.Class classType = getClassType(type);
125-
if (classType == null) {
126-
return null;
127-
}
128-
129-
JavaType.Parameterized parameterized = new JavaType.Parameterized(null, classType, singletonList(type));
123+
static J.FieldAccess newClassLiteral(JavaType.Class classType, JavaType originalType, J instanceOfClass) {
124+
JavaType.Parameterized parameterized = new JavaType.Parameterized(null, classType, singletonList(originalType));
130125
return new J.FieldAccess(
131126
randomId(),
132127
Space.EMPTY,
133128
Markers.EMPTY,
134-
className(type, qualified),
129+
instanceOfClass.withPrefix(Space.EMPTY), // Use the original expression directly
135130
new JLeftPadded<>(
136131
Space.EMPTY,
137132
new J.Identifier(randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), "class", parameterized, null),
@@ -141,7 +136,7 @@ static J.MemberReference newInstanceMethodReference(Expression containing, Strin
141136
);
142137
}
143138

144-
private static JavaType.@Nullable Class getClassType(@Nullable JavaType type) {
139+
static JavaType.@Nullable Class getClassType(@Nullable JavaType type) {
145140
if (type instanceof JavaType.Class) {
146141
JavaType.Class classType = (JavaType.Class) type;
147142
if ("java.lang.Class".equals(classType.getFullyQualifiedName())) {

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

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,11 @@ public J visitLambda(J.Lambda lambda, ExecutionContext ctx) {
100100
J j = instanceOf.getClazz();
101101
if ((j instanceof J.Identifier || j instanceof J.FieldAccess) &&
102102
instanceOf.getExpression() instanceof J.Identifier) {
103-
J.FieldAccess classLiteral = newClassLiteral(((TypeTree) j).getType(), j instanceof J.FieldAccess);
104-
if (classLiteral != null) {
103+
// Create the class literal directly from the original expression
104+
JavaType originalType = ((TypeTree) j).getType();
105+
JavaType.Class classType = getClassType(originalType);
106+
if (classType != null) {
107+
J.FieldAccess classLiteral = newClassLiteral(classType, originalType, j);
105108
//noinspection DataFlowIssue
106109
JavaType.FullyQualified rawClassType = ((JavaType.Parameterized) classLiteral.getType()).getType();
107110
Optional<JavaType.Method> isInstanceMethod = rawClassType.getMethods().stream().filter(m -> "isInstance".equals(m.getName())).findFirst();
@@ -123,11 +126,13 @@ public J visitLambda(J.Lambda lambda, ExecutionContext ctx) {
123126
J tree = j.getTree();
124127
if ((tree instanceof J.Identifier || tree instanceof J.FieldAccess) &&
125128
!(j.getType() instanceof JavaType.GenericTypeVariable)) {
126-
J.FieldAccess classLiteral = newClassLiteral(((Expression) tree).getType(), tree instanceof J.FieldAccess);
127-
if (classLiteral != null) {
129+
// Create the class literal directly from the original expression
130+
JavaType.Class classType = getClassType(((Expression) tree).getType());
131+
if (classType != null) {
132+
J.FieldAccess classLiteral = newClassLiteral(classType, ((Expression) tree).getType(), tree);
128133
//noinspection DataFlowIssue
129-
JavaType.FullyQualified classType = ((JavaType.Parameterized) classLiteral.getType()).getType();
130-
Optional<JavaType.Method> castMethod = classType.getMethods().stream().filter(m -> "cast".equals(m.getName())).findFirst();
134+
JavaType.FullyQualified fullClassType = ((JavaType.Parameterized) classLiteral.getType()).getType();
135+
Optional<JavaType.Method> castMethod = fullClassType.getMethods().stream().filter(m -> "cast".equals(m.getName())).findFirst();
131136
if (castMethod.isPresent()) {
132137
J.MemberReference updated = newInstanceMethodReference(classLiteral, castMethod.get(), lambda.getType()).withPrefix(lambda.getPrefix());
133138
doAfterVisit(service(ImportService.class).shortenFullyQualifiedTypeReferencesIn(updated));
@@ -252,9 +257,7 @@ private boolean hasSelectWhoseReferenceMightChange(MethodCall method) {
252257
JavaType.Variable fieldType = ((J.FieldAccess) select).getName().getFieldType();
253258
return fieldType != null && fieldType.getOwner() instanceof JavaType.Class && !fieldType.hasFlags(Flag.Final);
254259
}
255-
if (select instanceof J.NewClass || select instanceof J.Parentheses) {
256-
return true;
257-
}
260+
return select instanceof J.NewClass || select instanceof J.Parentheses;
258261
}
259262
return false;
260263
}

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

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,4 +1487,93 @@ public void run() {
14871487
)
14881488
);
14891489
}
1490+
1491+
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/744")
1492+
@Test
1493+
void methodReferenceNestedClassImportInvalid() {
1494+
rewriteRun(
1495+
//language=java
1496+
java(
1497+
"""
1498+
import java.util.List;
1499+
import java.util.Map.Entry;
1500+
1501+
public class Foo {
1502+
private void foo() {
1503+
List.of().stream().filter(i -> i instanceof Entry);
1504+
}
1505+
}
1506+
""",
1507+
"""
1508+
import java.util.List;
1509+
import java.util.Map.Entry;
1510+
1511+
public class Foo {
1512+
private void foo() {
1513+
List.of().stream().filter(Entry.class::isInstance);
1514+
}
1515+
}
1516+
"""
1517+
)
1518+
);
1519+
}
1520+
1521+
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/744")
1522+
@Test
1523+
void methodReferenceNestedClassFullyQualified() {
1524+
rewriteRun(
1525+
//language=java
1526+
java(
1527+
"""
1528+
import java.util.List;
1529+
1530+
public class Foo {
1531+
private void foo() {
1532+
List.of().stream().filter(i -> i instanceof java.util.Map.Entry);
1533+
}
1534+
}
1535+
""",
1536+
"""
1537+
import java.util.List;
1538+
import java.util.Map;
1539+
1540+
public class Foo {
1541+
private void foo() {
1542+
List.of().stream().filter(Map.Entry.class::isInstance);
1543+
}
1544+
}
1545+
"""
1546+
)
1547+
);
1548+
}
1549+
1550+
@Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/744")
1551+
@Test
1552+
void methodReferenceNestedClassCast() {
1553+
rewriteRun(
1554+
//language=java
1555+
java(
1556+
"""
1557+
import java.util.List;
1558+
import java.util.Map.Entry;
1559+
1560+
public class Foo {
1561+
private void foo() {
1562+
List.of().stream().map(i -> (Entry) i);
1563+
}
1564+
}
1565+
""",
1566+
"""
1567+
import java.util.List;
1568+
import java.util.Map.Entry;
1569+
1570+
public class Foo {
1571+
private void foo() {
1572+
List.of().stream().map(Entry.class::cast);
1573+
}
1574+
}
1575+
"""
1576+
)
1577+
);
1578+
}
14901579
}

0 commit comments

Comments
 (0)