mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-13 21:55:01 +07:00
method refs: simplify if first parameter is a receiver for method reference (IDEA-136882)
This commit is contained in:
+6
-5
@@ -263,13 +263,14 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
|
||||
if (element instanceof PsiMethodCallExpression) {
|
||||
final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)element;
|
||||
|
||||
final PsiMethod psiMethod = methodCall.resolveMethod();
|
||||
JavaResolveResult result = methodCall.resolveMethodGenerics();
|
||||
final PsiMethod psiMethod = (PsiMethod)result.getElement();
|
||||
if (psiMethod == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiReferenceExpression methodExpression = methodCall.getMethodExpression();
|
||||
final String qualifierByMethodCall = getQualifierTextByMethodCall(methodCall, functionalInterfaceType, parameters, psiMethod);
|
||||
final String qualifierByMethodCall = getQualifierTextByMethodCall(methodCall, functionalInterfaceType, parameters, psiMethod, result.getSubstitutor());
|
||||
if (qualifierByMethodCall != null) {
|
||||
return qualifierByMethodCall + "::" + ((PsiMethodCallExpression)element).getTypeArgumentList().getText() + methodExpression.getReferenceName();
|
||||
}
|
||||
@@ -324,7 +325,8 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
|
||||
private static String getQualifierTextByMethodCall(final PsiMethodCallExpression methodCall,
|
||||
final PsiType functionalInterfaceType,
|
||||
final PsiParameter[] parameters,
|
||||
final PsiMethod psiMethod) {
|
||||
final PsiMethod psiMethod,
|
||||
final PsiSubstitutor substitutor) {
|
||||
|
||||
final PsiExpression qualifierExpression = methodCall.getMethodExpression().getQualifierExpression();
|
||||
|
||||
@@ -332,7 +334,7 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
|
||||
LOG.assertTrue(containingClass != null);
|
||||
|
||||
if (qualifierExpression != null) {
|
||||
boolean isReceiverType = PsiMethodReferenceUtil.isReceiverType(functionalInterfaceType, containingClass, psiMethod);
|
||||
boolean isReceiverType = PsiMethodReferenceUtil.isReceiverType(PsiMethodReferenceUtil.getFirstParameterType(functionalInterfaceType, methodCall), containingClass, substitutor);
|
||||
return isReceiverType ? composeReceiverQualifierText(parameters, psiMethod, containingClass, qualifierExpression)
|
||||
: qualifierExpression.getText();
|
||||
}
|
||||
@@ -422,7 +424,6 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
|
||||
if (lambdaExpression == null) return;
|
||||
PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
|
||||
if (functionalInterfaceType == null || !functionalInterfaceType.isValid()) return;
|
||||
String functionalTypeText = functionalInterfaceType.getCanonicalText();
|
||||
final String methodRefText = createMethodReferenceText(element, functionalInterfaceType,
|
||||
lambdaExpression.getParameterList().getParameters());
|
||||
|
||||
|
||||
@@ -30,10 +30,10 @@ public class PsiMethodReferenceUtil {
|
||||
public static final Logger LOG = Logger.getInstance("#" + PsiMethodReferenceUtil.class.getName());
|
||||
|
||||
public static boolean hasReceiver(PsiType[] parameterTypes, QualifierResolveResult qualifierResolveResult, PsiMethodReferenceExpression methodRef) {
|
||||
if (parameterTypes.length > 0 &&
|
||||
if (parameterTypes.length > 0 &&
|
||||
!methodRef.isConstructor() &&
|
||||
isReceiverType(parameterTypes[0], qualifierResolveResult.getContainingClass(), qualifierResolveResult.getSubstitutor()) &&
|
||||
isStaticallyReferenced(methodRef)) {
|
||||
isStaticallyReferenced(methodRef) &&
|
||||
isReceiverType(parameterTypes[0], qualifierResolveResult.getContainingClass(), qualifierResolveResult.getSubstitutor())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -46,7 +46,7 @@ public class PsiMethodReferenceUtil {
|
||||
LOG.assertTrue(containingClass != null);
|
||||
PsiSubstitutor subst = result.getSubstitutor();
|
||||
PsiClass qContainingClass = getQualifierResolveResult(expression).getContainingClass();
|
||||
if (qContainingClass != null && isReceiverType(functionalInterfaceType, containingClass, (PsiMethod)resolve)) {
|
||||
if (qContainingClass != null && isReceiverType(getFirstParameterType(functionalInterfaceType, expression), qContainingClass, subst)) {
|
||||
subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst);
|
||||
LOG.assertTrue(subst != null);
|
||||
}
|
||||
@@ -202,53 +202,27 @@ public class PsiMethodReferenceUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isReceiverType(@Nullable PsiClass aClass, @Nullable PsiClass containingClass) {
|
||||
return InheritanceUtil.isInheritorOrSelf(aClass, containingClass, true);
|
||||
}
|
||||
|
||||
public static boolean isReceiverType(PsiType receiverType, @Nullable PsiClass containingClass, PsiSubstitutor psiSubstitutor) {
|
||||
if (containingClass != null) {
|
||||
receiverType = getExpandedType(receiverType, containingClass);
|
||||
//if P1, ..., Pn is not empty and P1 is a subtype of ReferenceType, then the method reference expression is treated as
|
||||
// if it were a method invocation expression with argument expressions of types P2, ...,Pn.
|
||||
public static boolean isReceiverType(@Nullable PsiType receiverType, PsiClass containingClass, PsiSubstitutor psiSubstitutor) {
|
||||
if (receiverType == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(receiverType);
|
||||
final PsiClass receiverClass = resolveResult.getElement();
|
||||
if (receiverClass != null && isReceiverType(receiverClass, containingClass)) {
|
||||
if (emptyOrRaw(containingClass, psiSubstitutor)) {
|
||||
return true;
|
||||
}
|
||||
final PsiSubstitutor derivedSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, receiverClass, psiSubstitutor);
|
||||
return derivedSubstitutor != null && TypeConversionUtil.isAssignable(JavaPsiFacade.getElementFactory(containingClass.getProject()).createType(containingClass, derivedSubstitutor), receiverType);
|
||||
}
|
||||
return false;
|
||||
return TypeConversionUtil.isAssignable(JavaPsiFacade.getElementFactory(containingClass.getProject()).createType(containingClass, psiSubstitutor),
|
||||
getExpandedType(receiverType, containingClass));
|
||||
}
|
||||
|
||||
private static boolean emptyOrRaw(PsiClass containingClass, PsiSubstitutor psiSubstitutor) {
|
||||
return PsiUtil.isRawSubstitutor(containingClass, psiSubstitutor) ||
|
||||
psiSubstitutor.getSubstitutionMap().isEmpty();
|
||||
}
|
||||
|
||||
public static boolean isReceiverType(PsiType functionalInterfaceType, PsiClass containingClass, @Nullable PsiMethod referencedMethod) {
|
||||
public static PsiType getFirstParameterType(PsiType functionalInterfaceType, PsiElement context) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final MethodSignature function = LambdaUtil.getFunction(resolveResult.getElement());
|
||||
if (function != null) {
|
||||
final int interfaceMethodParamsLength = function.getParameterTypes().length;
|
||||
if (interfaceMethodParamsLength > 0) {
|
||||
final PsiType firstParamType = resolveResult.getSubstitutor().substitute(function.getParameterTypes()[0]);
|
||||
boolean isReceiver = isReceiverType(firstParamType,
|
||||
containingClass, PsiUtil.resolveGenericsClassInType(firstParamType).getSubstitutor());
|
||||
if (isReceiver) {
|
||||
if (referencedMethod == null){
|
||||
if (interfaceMethodParamsLength == 1) return true;
|
||||
return false;
|
||||
}
|
||||
if (referencedMethod.getParameterList().getParametersCount() != interfaceMethodParamsLength - 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
PsiType type = resolveResult.getSubstitutor().substitute(function.getParameterTypes()[0]);
|
||||
return type != null ? PsiUtil.captureToplevelWildcards(type, context) : null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiType getExpandedType(PsiType type, @NotNull PsiElement typeElement) {
|
||||
|
||||
+1
-2
@@ -20,7 +20,6 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiImplUtil;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
|
||||
@@ -480,7 +479,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
|
||||
PsiClass qContainingClass = PsiMethodReferenceUtil.getQualifierResolveResult(this).getContainingClass();
|
||||
if (qContainingClass != null && containingClass != null &&
|
||||
PsiMethodReferenceUtil.isReceiverType(left, containingClass, (PsiMethod)resolve)) {
|
||||
PsiMethodReferenceUtil.isReceiverType(PsiMethodReferenceUtil.getFirstParameterType(left, this), qContainingClass, subst)) {
|
||||
subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst);
|
||||
LOG.assertTrue(subst != null);
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
class Test {
|
||||
|
||||
static class Base {
|
||||
public BigDecimal getTotal() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void foo(List<? extends Base> list, List<Base> list1) {
|
||||
System.out.println(add(list, Base::getTotal));
|
||||
list1.forEach(Base::getTotal);
|
||||
}
|
||||
|
||||
|
||||
public static <T> BigDecimal add(Collection<T> objectsThatHaveBigDecimals, Function<T, ? extends BigDecimal> functionToGet) {
|
||||
return objectsThatHaveBigDecimals == null ? null : objectsThatHaveBigDecimals.stream().map(functionToGet).reduce(null, Test::add);
|
||||
}
|
||||
|
||||
public static BigDecimal add(BigDecimal... sequence) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+4
@@ -382,6 +382,10 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
public void testSecondSearchIfFirstParameterIsASubtypeOfReferenceTypeFromExpressionDeclaration() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user