fix cast introduction in LambdaCanBeMethodReferenceInspection#replaceLambdaWithMethodReference

This commit is contained in:
Tagir Valeev
2016-10-05 12:24:55 +07:00
parent c649917fd3
commit 46f9ce3e03
7 changed files with 77 additions and 51 deletions
@@ -232,7 +232,7 @@ public class ComparatorCombinatorsInspection extends BaseJavaBatchLocalInspectio
PsiParameter[] parameters = lambda.getParameterList().getParameters();
PsiElement body = lambda.getBody();
if (body == null) return;
if (LambdaCanBeMethodReferenceInspection.replaceLambdaWithMethodReference(factory, lambda) == lambda) {
if (LambdaCanBeMethodReferenceInspection.replaceLambdaWithMethodReference(lambda) == lambda) {
PsiParameter parameter = parameters[0];
String name = parameter.getName();
SuggestedNameInfo nameCandidate = null;
@@ -308,27 +308,18 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
public static void replaceAllLambdasWithMethodReferences(PsiElement root) {
Collection<PsiLambdaExpression> lambdas = PsiTreeUtil.findChildrenOfType(root, PsiLambdaExpression.class);
if(!lambdas.isEmpty()) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(root.getProject());
for(PsiLambdaExpression lambda : lambdas) {
replaceLambdaWithMethodReference(factory, lambda);
replaceLambdaWithMethodReference(lambda);
}
}
}
public static PsiExpression replaceLambdaWithMethodReference(PsiElementFactory factory, PsiLambdaExpression lambda) {
PsiType type = lambda.getFunctionalInterfaceType();
if(type == null) return lambda;
String methodReference =
convertToMethodReference(lambda.getBody(), lambda.getParameterList().getParameters(), type, lambda);
if(methodReference == null) return lambda;
PsiTypeCastExpression replacement = (PsiTypeCastExpression)lambda.replace(
factory.createExpressionFromText("(" + lambda.getFunctionalInterfaceType().getCanonicalText() + ")" + methodReference, lambda));
if (RedundantCastUtil.isCastRedundant(replacement)) {
final PsiExpression operand = replacement.getOperand();
LOG.assertTrue(operand != null);
return (PsiExpression)replacement.replace(operand);
}
return replacement;
@NotNull
public static PsiExpression replaceLambdaWithMethodReference(@NotNull PsiLambdaExpression lambda) {
PsiElement body = LambdaUtil.extractSingleExpressionFromBody(lambda.getBody());
final PsiExpression candidate = new LambdaCanBeMethodReferenceInspection()
.canBeMethodReferenceProblem(body, lambda.getParameterList().getParameters(), lambda.getFunctionalInterfaceType(), lambda);
return tryConvertToMethodReference(lambda, candidate);
}
private static boolean checkQualifier(PsiElement qualifier) {
@@ -599,34 +590,46 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
if (!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(element, PsiLambdaExpression.class);
if (lambdaExpression == null) return;
PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
if (functionalInterfaceType == null || !functionalInterfaceType.isValid()) return;
final PsiType denotableFunctionalInterfaceType = RefactoringChangeUtil.getTypeByExpression(lambdaExpression);
if (denotableFunctionalInterfaceType == null) return;
Collection<PsiComment> comments = ContainerUtil.map(PsiTreeUtil.findChildrenOfType(lambdaExpression, PsiComment.class),
(comment) -> (PsiComment)comment.copy());
final String methodRefText = createMethodReferenceText(element, functionalInterfaceType,
lambdaExpression.getParameterList().getParameters());
if (methodRefText != null) {
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final PsiExpression psiExpression = factory.createExpressionFromText(methodRefText, lambdaExpression);
final SmartTypePointer typePointer = SmartTypePointerManager.getInstance(project).createSmartTypePointer(denotableFunctionalInterfaceType);
PsiElement replace = lambdaExpression.replace(psiExpression);
final PsiType functionalTypeAfterReplacement = GenericsUtil.getVariableTypeByExpressionType(((PsiMethodReferenceExpression)replace).getFunctionalInterfaceType());
functionalInterfaceType = typePointer.getType();
if (functionalTypeAfterReplacement == null || functionalInterfaceType != null && !functionalTypeAfterReplacement.equals(functionalInterfaceType)) { //ambiguity
final PsiTypeCastExpression cast = (PsiTypeCastExpression)factory.createExpressionFromText("(A)a", replace);
cast.getCastType().replace(factory.createTypeElement(functionalInterfaceType));
cast.getOperand().replace(replace);
replace = replace.replace(cast);
}
AnonymousCanBeLambdaInspection.restoreComments(comments, replace);
JavaCodeStyleManager.getInstance(project).shortenClassReferences(replace);
}
tryConvertToMethodReference(lambdaExpression, element);
}
}
@NotNull
static PsiExpression tryConvertToMethodReference(@NotNull PsiLambdaExpression lambda, PsiElement body) {
Project project = lambda.getProject();
PsiType functionalInterfaceType = lambda.getFunctionalInterfaceType();
if (functionalInterfaceType == null || !functionalInterfaceType.isValid()) return lambda;
final PsiType denotableFunctionalInterfaceType = RefactoringChangeUtil.getTypeByExpression(lambda);
if (denotableFunctionalInterfaceType == null) return lambda;
Collection<PsiComment> comments = ContainerUtil.map(PsiTreeUtil.findChildrenOfType(lambda, PsiComment.class),
(comment) -> (PsiComment)comment.copy());
final String methodRefText = createMethodReferenceText(body, functionalInterfaceType, lambda.getParameterList().getParameters());
if (methodRefText != null) {
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
final PsiExpression psiExpression = factory.createExpressionFromText(methodRefText, lambda);
final SmartTypePointer typePointer = SmartTypePointerManager.getInstance(project).createSmartTypePointer(denotableFunctionalInterfaceType);
PsiExpression replace = (PsiExpression)lambda.replace(psiExpression);
final PsiType functionalTypeAfterReplacement = GenericsUtil.getVariableTypeByExpressionType(((PsiMethodReferenceExpression)replace).getFunctionalInterfaceType());
functionalInterfaceType = typePointer.getType();
if (functionalInterfaceType != null && (functionalTypeAfterReplacement == null ||
!functionalTypeAfterReplacement.equals(functionalInterfaceType))) { //ambiguity
final PsiTypeCastExpression cast = (PsiTypeCastExpression)factory.createExpressionFromText("(A)a", replace);
PsiTypeElement castType = cast.getCastType();
LOG.assertTrue(castType != null);
castType.replace(factory.createTypeElement(functionalInterfaceType));
PsiExpression castOperand = cast.getOperand();
LOG.assertTrue(castOperand != null);
castOperand.replace(replace);
replace = (PsiExpression)replace.replace(cast);
}
AnonymousCanBeLambdaInspection.restoreComments(comments, replace);
JavaCodeStyleManager.getInstance(project).shortenClassReferences(replace);
return replace;
}
return lambda;
}
}
@@ -285,8 +285,7 @@ public class IntroduceParameterDialog extends RefactoringDialog {
if (myCbCollapseToLambda.isVisible() && myCbCollapseToLambda.isSelected() && parameterInitializer != null) {
PsiExpression lambda = AnonymousCanBeLambdaInspection.replaceAnonymousWithLambda(parameterInitializer, selectedType);
if (lambda != null) {
lambda = LambdaCanBeMethodReferenceInspection.replaceLambdaWithMethodReference(JavaPsiFacade.getElementFactory(getProject()),
(PsiLambdaExpression)lambda);
lambda = LambdaCanBeMethodReferenceInspection.replaceLambdaWithMethodReference((PsiLambdaExpression)lambda);
processor.setParameterInitializer(lambda);
}
}
@@ -0,0 +1,10 @@
// "Replace with anyMatch()" "true"
import java.util.*;
public class Main {
public List<? extends CharSequence> getList() {return Arrays.asList("a");}
public boolean test() {
return getList().stream().map(CharSequence::toString).anyMatch(s -> !s.isEmpty());
}
}
@@ -3,12 +3,11 @@
import java.awt.*;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
public class Main {
private Point field = new Point(0, 0);
public Point find(List<Point> points) {
return points.stream().filter((Predicate<Point>) Objects::nonNull).findFirst().orElse(field);
return points.stream().filter(Objects::nonNull).findFirst().orElse(field);
}
}
@@ -3,12 +3,11 @@
import java.awt.*;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
public class Main {
private static Point ZERO = new Point(0, 0);
public static Point find(List<Point> points) {
return points.stream().filter((Predicate<Point>) Objects::nonNull).findFirst().orElse(ZERO);
return points.stream().filter(Objects::nonNull).findFirst().orElse(ZERO);
}
}
@@ -0,0 +1,16 @@
// "Replace with anyMatch()" "true"
import java.util.*;
public class Main {
public List<? extends CharSequence> getList() {return Arrays.asList("a");}
public boolean test() {
for(CharSequence cs : ge<caret>tList()) {
String s = cs.toString();
if(!s.isEmpty()) {
return true;
}
}
return false;
}
}