method ref -> lambda: check functional interface type after replacement

IDEA-184178
This commit is contained in:
Anna.Kozlova
2017-12-22 16:23:22 +01:00
parent 8af1fe8bcc
commit 2999cda37b
4 changed files with 38 additions and 29 deletions
@@ -20,14 +20,12 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
@@ -87,7 +85,7 @@ public class LambdaRefactoringUtil {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(referenceExpression.getProject());
PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)elementFactory.createExpressionFromText(lambda, referenceExpression);
final PsiType functionalInterfaceType = referenceExpression.getFunctionalInterfaceType();
boolean needToSpecifyFormalTypes = !doNotAddParameterTypes && !isInferredSameTypeAfterConversion(lambdaExpression, referenceExpression, functionalInterfaceType);
boolean needToSpecifyFormalTypes = !doNotAddParameterTypes && !isInferredSameTypeAfterConversion(lambdaExpression, referenceExpression);
if (needToSpecifyFormalTypes) {
PsiParameterList typedParamList = specifyLambdaParameterTypes(functionalInterfaceType, lambdaExpression);
if (typedParamList == null) {
@@ -281,30 +279,20 @@ public class LambdaRefactoringUtil {
}
private static boolean isInferredSameTypeAfterConversion(PsiLambdaExpression lambdaExpression,
PsiMethodReferenceExpression methodReferenceExpression,
PsiType functionalInterfaceType) {
PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodReferenceExpression.getParent());
if (!(parent instanceof PsiExpressionList)) {
PsiMethodReferenceExpression methodReferenceExpression) {
PsiCall call = LambdaUtil.treeWalkUp(methodReferenceExpression);
if (call == null) {
return true;
}
PsiElement gParent = parent.getParent();
if (gParent instanceof PsiCall) {
if (gParent instanceof PsiCallExpression && ((PsiCallExpression)gParent).getTypeArguments().length > 0) {
return true;
}
JavaResolveResult result = ((PsiCall)gParent).resolveMethodGenerics();
if (result instanceof MethodCandidateInfo) {
PsiMethod method = ((MethodCandidateInfo)result).getElement();
if (!method.hasTypeParameters()) {
return true;
}
PsiExpression[] args = ((PsiExpressionList)parent).getExpressions();
int lambdaIdx = LambdaUtil.getLambdaIdx((PsiExpressionList)parent, methodReferenceExpression);
args[lambdaIdx] = lambdaExpression;
final PsiParameter[] methodParams = method.getParameterList().getParameters();
final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE, args, true);
PsiType formalTargetType = substitutor.substitute(PsiTypesUtil.getParameterType(methodParams, lambdaIdx, ((MethodCandidateInfo)result).isVarargs()));
return functionalInterfaceType.equals(FunctionalInterfaceParameterizationUtil.getGroundTargetType(formalTargetType));
Object marker = new Object();
PsiTreeUtil.mark(methodReferenceExpression, marker);
PsiCall copyTopLevelCall = LambdaUtil.copyTopLevelCall(call);
if (copyTopLevelCall != null) {
PsiMethodReferenceExpression methodReferenceInCopy = (PsiMethodReferenceExpression)PsiTreeUtil.releaseMark(copyTopLevelCall, marker);
if (methodReferenceInCopy != null) {
PsiType functionalInterfaceType = methodReferenceInCopy.getFunctionalInterfaceType();
PsiLambdaExpression lambdaCopy = (PsiLambdaExpression)methodReferenceInCopy.replace(lambdaExpression);
return Comparing.equal(functionalInterfaceType, lambdaCopy.getFunctionalInterfaceType());
}
}
return false;
@@ -0,0 +1,11 @@
import java.util.Comparator;
class MyTest {
void setComparator(Comparator<?> comparator) {}
String getValue() {
return "";
}
{
setComparator(Comparator.comparing((MyTest myTest) -> myTest.getValue()));
}
}
@@ -0,0 +1,11 @@
import java.util.Comparator;
class MyTest {
void setComparator(Comparator<?> comparator) {}
String getValue() {
return "";
}
{
setComparator(Comparator.comparing(MyTest::<caret>getValue));
}
}
@@ -143,9 +143,8 @@ public class MethodRefCanBeReplacedWithLambdaFixTest extends IGQuickFixesTestCas
doTest();
}
public void testNewArrayMethodReferenceHasNoSideEffects() {
doTest();
}
public void testNewArrayMethodReferenceHasNoSideEffects() { doTest(); }
public void testExplicitTypeRequired() { doTest(); }
public void testEnsureNoConversionIsSuggestedWhenLambdaWithoutCantBeInferredAndFormalParametersAreNotDenotable() {
assertQuickfixNotAvailable();