[java-inspections] LambdaCanBeMethodReference: disable conversion in many cases when cast is required

Fixes IDEA-267865 Add a option for Java's method reference inspection that ignore lambda which can't convert into method reference without a cast

GitOrigin-RevId: b6f762383d6ba1ef19a5de36e0ad53d107ba4e80
This commit is contained in:
Tagir Valeev
2021-10-08 18:36:11 +07:00
committed by intellij-monorepo-bot
parent 9f3d7463a1
commit bcb843dd8f
7 changed files with 43 additions and 51 deletions

View File

@@ -1,21 +0,0 @@
// "Replace lambda with method reference" "true"
import java.util.*;
class IDEA100385 {
void foo(N<Double> n, List<Double> l){
n.forEach((DoubleConsumer) l::add);
}
static interface N<E> {
default void forEach(DoubleConsumer consumer) {
}
void forEach(Consumer<? super E> consumer);
}
interface DoubleConsumer {
void _(double d);
}
interface Consumer<T> {
public void accept(T t);
}
}

View File

@@ -1,17 +0,0 @@
// "Replace lambda with method reference" "true"
import java.util.prefs.Preferences;
class Test {
private Preferences preferences;
{
foo(short.class, (Writer<Short>) Preferences::putInt);
}
private <T> void foo(Class<T> type, Writer<T> writer) {}
interface Writer<T> {
void write(Preferences preferences, String key, T value);
}
}

View File

@@ -1,4 +1,4 @@
// "Replace lambda with method reference" "true"
// "Replace lambda with method reference" "false"
import java.util.*;
class IDEA100385 {
void foo(N<Double> n, List<Double> l){

View File

@@ -0,0 +1,19 @@
// "Replace lambda with method reference" "false"
import java.util.function.Function;
import java.util.function.Supplier;
class Foo {}
class Bar {}
class Something {
static void stuff(Function<Foo, Bar> foo2bar) {}
static void stuff(Supplier<Bar> sup4Bar) {}
}
class Something2 {
static Bar bar(Foo foo) { return null; }
static Bar bar() { return null; }
}
class Main {
public static void main(String[] args) {
Something.stuff(foo -> <caret>Something2.bar(foo));
Something.stuff(() -> Something2.bar());
}
}

View File

@@ -1,4 +1,4 @@
// "Replace lambda with method reference" "true"
// "Replace lambda with method reference" "false"
import java.util.prefs.Preferences;
class Test {

View File

@@ -1,6 +1,5 @@
// "Replace with forEach" "true"
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
public class Main {
@@ -12,6 +11,6 @@ public class Main {
static boolean isGood(A a) {}
public long test() {
Stream.iterate(new A(), (UnaryOperator<A>) Main::isGood, a -> a.next()).filter(a -> a.x < 3).forEach(System.out::println);
Stream.iterate(new A(), a -> isGood(a), a -> a.next()).filter(a -> a.x < 3).forEach(System.out::println);
}
}

View File

@@ -64,13 +64,9 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI
public void visitLambdaExpression(PsiLambdaExpression expression) {
super.visitLambdaExpression(expression);
final PsiElement body = expression.getBody();
final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType == null) return;
MethodReferenceCandidate methodRefCandidate = extractMethodReferenceCandidateExpression(body);
if (methodRefCandidate == null) return;
final PsiExpression candidate =
canBeMethodReferenceProblem(expression.getParameterList().getParameters(), functionalInterfaceType, null,
methodRefCandidate.myExpression);
final PsiExpression candidate = getLambdaToMethodReferenceConversionCandidate(expression, methodRefCandidate.myExpression);
if (candidate == null) return;
ProblemHighlightType type;
if (methodRefCandidate.mySafeQualifier && methodRefCandidate.myConformsCodeStyle) {
@@ -93,6 +89,24 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI
};
}
@Nullable
private static PsiExpression getLambdaToMethodReferenceConversionCandidate(@NotNull PsiLambdaExpression expression,
@NotNull PsiExpression methodRefCandidate) {
PsiParameter[] parameters = expression.getParameterList().getParameters();
PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType == null) return null;
final PsiExpression candidate = canBeMethodReferenceProblem(parameters, functionalInterfaceType, null, methodRefCandidate);
if (candidate == null) return null;
boolean safeLambdaReplacement = LambdaUtil.isSafeLambdaReplacement(expression, () -> {
String text = createMethodReferenceText(methodRefCandidate, functionalInterfaceType, parameters);
// We already did the same operation inside canBeMethodReferenceProblem
LOG.assertTrue(text != null);
return JavaPsiFacade.getElementFactory(expression.getProject()).createExpressionFromText(text, expression);
});
if (!safeLambdaReplacement) return null;
return candidate;
}
@Nullable
public static PsiExpression canBeMethodReferenceProblem(@Nullable final PsiElement body,
final PsiVariable[] parameters,
@@ -305,9 +319,7 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI
public static PsiExpression replaceLambdaWithMethodReference(@NotNull PsiLambdaExpression lambda) {
MethodReferenceCandidate methodRefCandidate = extractMethodReferenceCandidateExpression(lambda.getBody());
if (methodRefCandidate == null || !methodRefCandidate.mySafeQualifier || !methodRefCandidate.myConformsCodeStyle) return lambda;
PsiExpression candidate =
canBeMethodReferenceProblem(lambda.getParameterList().getParameters(), lambda.getFunctionalInterfaceType(), lambda,
methodRefCandidate.myExpression);
PsiExpression candidate = getLambdaToMethodReferenceConversionCandidate(lambda, methodRefCandidate.myExpression);
return tryConvertToMethodReference(lambda, candidate);
}
@@ -614,7 +626,7 @@ public class LambdaCanBeMethodReferenceInspection extends AbstractBaseJavaLocalI
}
@NotNull
static PsiExpression tryConvertToMethodReference(@NotNull PsiLambdaExpression lambda, PsiElement body) {
private static PsiExpression tryConvertToMethodReference(@NotNull PsiLambdaExpression lambda, PsiElement body) {
Project project = lambda.getProject();
PsiType functionalInterfaceType = lambda.getFunctionalInterfaceType();
if (functionalInterfaceType == null || !functionalInterfaceType.isValid()) return lambda;