From 065a70544087f19aa8c07504c807591e0b0c04e2 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 28 May 2026 12:18:49 +0200 Subject: [PATCH] Use receiver type for unbound instance method reference in `ReplaceLambdaWithMethodReference` Previously the recipe used the method's declaring type to construct the class name, which produced uncompilable references like `Base::getValue` (with an inaccessible import) when the declaring class was package-private and the receiver was a public subclass. --- .../ReplaceLambdaWithMethodReference.java | 9 ++- .../ReplaceLambdaWithMethodReferenceTest.java | 56 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openrewrite/staticanalysis/ReplaceLambdaWithMethodReference.java b/src/main/java/org/openrewrite/staticanalysis/ReplaceLambdaWithMethodReference.java index b00fddfdf..f07b3e67a 100644 --- a/src/main/java/org/openrewrite/staticanalysis/ReplaceLambdaWithMethodReference.java +++ b/src/main/java/org/openrewrite/staticanalysis/ReplaceLambdaWithMethodReference.java @@ -211,7 +211,14 @@ public J visitLambda(J.Lambda lambda, ExecutionContext ctx) { if (isLambdaInGenericAndOverloadedContext()) { return l; } - J.MemberReference updated = newStaticMethodReference(methodType, true, lambda.getType()).withPrefix(lambda.getPrefix()); + JavaType.FullyQualified containingType = methodType.getDeclaringType(); + if (!methodType.hasFlags(Flag.Static) && select != null) { + JavaType.FullyQualified selectType = TypeUtils.asFullyQualified(select.getType()); + if (selectType != null) { + containingType = selectType; + } + } + J.MemberReference updated = newInstanceMethodReference(className(containingType, true), methodType, lambda.getType()).withPrefix(lambda.getPrefix()); doAfterVisit(service(ImportService.class).shortenFullyQualifiedTypeReferencesIn(updated)); return updated; } diff --git a/src/test/java/org/openrewrite/staticanalysis/ReplaceLambdaWithMethodReferenceTest.java b/src/test/java/org/openrewrite/staticanalysis/ReplaceLambdaWithMethodReferenceTest.java index a0ebbd1fc..d5c04d5a7 100644 --- a/src/test/java/org/openrewrite/staticanalysis/ReplaceLambdaWithMethodReferenceTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/ReplaceLambdaWithMethodReferenceTest.java @@ -1878,6 +1878,62 @@ record R(String s) {} ); } + @Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/906") + @Test + void useReceiverTypeWhenDeclaringTypeIsPackagePrivate() { + rewriteRun( + //language=java + java( + """ + package com.helloworld.internal; + + import java.util.Optional; + + abstract class Base { + public Optional getValue() { + return Optional.empty(); + } + } + """ + ), + //language=java + java( + """ + package com.helloworld.internal; + + public class Child extends Base {} + """ + ), + //language=java + java( + """ + package com.helloworld; + + import com.helloworld.internal.Child; + import java.util.Optional; + + public class Main { + String get(final Optional opt) { + return opt.flatMap(s -> s.getValue()).orElse(""); + } + } + """, + """ + package com.helloworld; + + import com.helloworld.internal.Child; + import java.util.Optional; + + public class Main { + String get(final Optional opt) { + return opt.flatMap(Child::getValue).orElse(""); + } + } + """ + ) + ); + } + @Issue("https://github.com/openrewrite/rewrite-static-analysis/issues/20") @Test void castToTypeParameterInLambda() {