diff --git a/src/main/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCast.java b/src/main/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCast.java index d7635a5b0..0b451e54a 100644 --- a/src/main/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCast.java +++ b/src/main/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCast.java @@ -67,6 +67,10 @@ public J visitTypeCast(J.TypeCast typeCast, ExecutionContext ctx) { return visited; } + if (isSignaturePolymorphic(typeCast.getExpression())) { + return visited; + } + Cursor parent = getCursor().dropParentUntil(is -> is instanceof J.VariableDeclarations || is instanceof J.Lambda || is instanceof J.Return || @@ -230,6 +234,18 @@ public J visitParentheses(J.Parentheses parens, ExecutionContex return parentheses; } + /// Signature-polymorphic methods (JLS 15.12.3) take their return type from the enclosing cast, so removing it breaks compilation. + private boolean isSignaturePolymorphic(Expression expression) { + Expression expr = expression.unwrap(); + if (!(expr instanceof J.MethodInvocation)) { + return false; + } + JavaType.Method methodType = ((J.MethodInvocation) expr).getMethodType(); + return methodType != null && + (TypeUtils.isOfClassType(methodType.getDeclaringType(), "java.lang.invoke.MethodHandle") || + TypeUtils.isOfClassType(methodType.getDeclaringType(), "java.lang.invoke.VarHandle")); + } + private boolean returnsDeclaredTypeParameter(Expression expression) { if (!(expression instanceof J.MethodInvocation)) { return false; diff --git a/src/test/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCastTest.java b/src/test/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCastTest.java index 6b11c2191..bb17c0b0a 100644 --- a/src/test/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCastTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/RemoveRedundantTypeCastTest.java @@ -930,4 +930,46 @@ static void sink(Object... args) {} ) ); } + + @Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/1024") + @Test + void doNotRemoveCastOnMethodHandleInvoke() { + rewriteRun( + //language=java + java( + """ + import java.lang.invoke.MethodHandle; + + class Example { + String hello(MethodHandle handle) throws Throwable { + return (String) handle.invoke(); + } + + void assign(MethodHandle handle) throws Throwable { + String s = (String) handle.invokeExact(); + } + } + """ + ) + ); + } + + @Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/1024") + @Test + void doNotRemoveCastOnVarHandleAccessor() { + rewriteRun( + //language=java + java( + """ + import java.lang.invoke.VarHandle; + + class Example { + String read(VarHandle handle, Object target) { + return (String) handle.get(target); + } + } + """ + ) + ); + } }