abandon isFullyInferred from LambdaUtil

This commit is contained in:
Anna Kozlova
2017-06-22 15:54:29 +03:00
parent 1736707bff
commit 1307ac8e78
6 changed files with 8 additions and 192 deletions
@@ -112,37 +112,8 @@ public class LambdaHighlightingUtil {
if (aClass instanceof PsiTypeParameter) return null; //should be logged as cyclic inference
MethodSignature functionalMethod = LambdaUtil.getFunction(aClass);
if (functionalMethod != null && functionalMethod.getTypeParameters().length > 0) return "Target method is generic";
if (checkReturnTypeApplicable(resolveResult, aClass)) {
return "No instance of type " + functionalInterfaceType.getPresentableText() + " exists so that lambda expression can be type-checked";
}
return checkInterfaceFunctional(aClass);
}
return functionalInterfaceType.getPresentableText() + " is not a functional interface";
}
private static boolean checkReturnTypeApplicable(PsiClassType.ClassResolveResult resolveResult, final PsiClass aClass) {
final MethodSignature methodSignature = LambdaUtil.getFunction(aClass);
if (methodSignature == null) return false;
for (PsiTypeParameter parameter : aClass.getTypeParameters()) {
if (parameter.getExtendsListTypes().length == 0) continue;
final PsiType substitution = resolveResult.getSubstitutor().substitute(parameter);
if (substitution instanceof PsiWildcardType && !((PsiWildcardType)substitution).isBounded()) {
boolean depends = false;
for (PsiType paramType : methodSignature.getParameterTypes()) {
if (LambdaUtil.depends(paramType, new LambdaUtil.TypeParamsChecker((PsiMethod)null, aClass) {
@Override
public boolean startedInference() {
return true;
}
}, parameter)) {
depends = true;
break;
}
}
if (!depends) return true;
}
}
return false;
}
}
@@ -23,9 +23,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -55,7 +52,7 @@ public class RedundantLambdaParameterTypeInspection extends BaseJavaBatchLocalIn
if (parameter.getTypeElement() == null) return false;
}
if (parameters.length == 0) return false;
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, true);
final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
final PsiElement lambdaParent = expression.getParent();
if (lambdaParent instanceof PsiExpressionList) {
@@ -67,36 +64,15 @@ public class RedundantLambdaParameterTypeInspection extends BaseJavaBatchLocalIn
final int idx = LambdaUtil.getLambdaIdx((PsiExpressionList)lambdaParent, expression);
if (idx < 0) return false;
final PsiTypeParameter[] typeParameters = method.getTypeParameters();
final PsiExpression[] arguments = ((PsiExpressionList)lambdaParent).getExpressions();
final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(parameterList.getProject());
arguments[idx] = javaPsiFacade.getElementFactory().createExpressionFromText(
"(" + StringUtil.join(expression.getParameterList().getParameters(), PsiParameter::getName, ", ") + ") -> {}", expression);
final PsiParameter[] methodParams = method.getParameterList().getParameters();
final PsiSubstitutor substitutor = javaPsiFacade.getResolveHelper()
.inferTypeArguments(typeParameters, methodParams, arguments, ((MethodCandidateInfo)resolveResult).getSiteSubstitutor(),
gParent, DefaultParameterTypeInferencePolicy.INSTANCE);
for (PsiTypeParameter parameter : typeParameters) {
final PsiType psiType = substitutor.substitute(parameter);
if (psiType == null || dependsOnTypeParams(psiType, expression, parameter)) return false;
PsiCallExpression copy = (PsiCallExpression)gParent.copy();
PsiLambdaExpression lambdaToStripTypeParameters = (PsiLambdaExpression)copy.getArgumentList().getExpressions()[idx];
for (PsiParameter parameter : lambdaToStripTypeParameters.getParameterList().getParameters()) {
parameter.getTypeElement().delete();
}
final PsiType paramType;
if (idx < methodParams.length) {
paramType = methodParams[idx].getType();
}
else {
final PsiParameter lastParam = methodParams[methodParams.length - 1];
if (!lastParam.isVarArgs()) return false;
paramType = ((PsiEllipsisType)lastParam.getType()).getComponentType();
}
return functionalInterfaceType.isAssignableFrom(substitutor.substitute(paramType));
return functionalInterfaceType.equals(lambdaToStripTypeParameters.getFunctionalInterfaceType());
}
}
if (!LambdaUtil.isLambdaFullyInferred(expression, functionalInterfaceType)) {
return false;
}
return true;
}
return false;
@@ -118,13 +94,6 @@ public class RedundantLambdaParameterTypeInspection extends BaseJavaBatchLocalIn
}
}
private static boolean dependsOnTypeParams(PsiType type,
PsiLambdaExpression expr,
PsiTypeParameter param2Check) {
return LambdaUtil.depends(type, new LambdaUtil.TypeParamsChecker(expr, PsiUtil
.resolveGenericsClassInType(LambdaUtil.getFunctionalInterfaceType(expr, false)).getElement()), param2Check);
}
private static class LambdaParametersFix implements LocalQuickFix {
@Nls
@NotNull
@@ -154,15 +154,6 @@ public class LambdaUtil {
context instanceof PsiArrayInitializerExpression;
}
public static boolean isLambdaFullyInferred(PsiLambdaExpression expression, PsiType functionalInterfaceType) {
final boolean hasParams = expression.getParameterList().getParametersCount() > 0;
if (hasParams || !PsiType.VOID.equals(getFunctionalInterfaceReturnType(functionalInterfaceType))) { //todo check that void lambdas without params check
return !dependsOnTypeParams(functionalInterfaceType, functionalInterfaceType, expression);
}
return true;
}
@Contract("null -> null")
@Nullable
public static MethodSignature getFunction(final PsiClass psiClass) {
@@ -348,23 +339,6 @@ public class LambdaUtil {
return -1;
}
public static boolean dependsOnTypeParams(PsiType type,
PsiType functionalInterfaceType,
PsiElement lambdaExpression,
PsiTypeParameter... param2Check) {
return depends(type, new TypeParamsChecker(lambdaExpression,
PsiUtil.resolveClassInType(functionalInterfaceType)), param2Check);
}
public static boolean depends(PsiType type, TypeParamsChecker visitor, PsiTypeParameter... param2Check) {
if (!visitor.startedInference()) return false;
final Boolean accept = type.accept(visitor);
if (param2Check.length > 0) {
return visitor.used(param2Check);
}
return accept != null && accept.booleanValue();
}
@Nullable
public static PsiType getFunctionalInterfaceType(PsiElement expression, final boolean tryToSubstitute) {
PsiElement parent = expression.getParent();
@@ -887,99 +861,4 @@ public class LambdaUtil {
return expression instanceof PsiReferenceExpression &&
((PsiReferenceExpression)expression).isReferenceTo(parameters.getParameters()[0]);
}
public static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
private PsiMethod myMethod;
private final PsiClass myClass;
public final Set<PsiTypeParameter> myUsedTypeParams = new HashSet<>();
public TypeParamsChecker(PsiElement expression, PsiClass aClass) {
myClass = aClass;
PsiElement parent = expression != null ? expression.getParent() : null;
while (parent instanceof PsiParenthesizedExpression) {
parent = parent.getParent();
}
if (parent instanceof PsiExpressionList) {
final PsiElement gParent = parent.getParent();
if (gParent instanceof PsiCall) {
final MethodCandidateInfo.CurrentCandidateProperties pair = MethodCandidateInfo.getCurrentMethod(parent);
myMethod = pair != null ? pair.getMethod() : null;
if (myMethod == null) {
myMethod = ((PsiCall)gParent).resolveMethod();
}
if (myMethod != null && PsiTreeUtil.isAncestor(myMethod, expression, false)) {
myMethod = null;
}
}
}
}
public boolean startedInference() {
return myMethod != null;
}
@Override
public Boolean visitClassType(PsiClassType classType) {
boolean used = false;
for (PsiType paramType : classType.getParameters()) {
final Boolean paramAccepted = paramType.accept(this);
used |= paramAccepted != null && paramAccepted.booleanValue();
}
final PsiClass resolve = classType.resolve();
if (resolve instanceof PsiTypeParameter) {
final PsiTypeParameter typeParameter = (PsiTypeParameter)resolve;
if (check(typeParameter)) {
myUsedTypeParams.add(typeParameter);
return true;
}
}
return used;
}
@Nullable
@Override
public Boolean visitWildcardType(PsiWildcardType wildcardType) {
final PsiType bound = wildcardType.getBound();
if (bound != null) return bound.accept(this);
return false;
}
@Nullable
@Override
public Boolean visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
return true;
}
@Nullable
@Override
public Boolean visitLambdaExpressionType(PsiLambdaExpressionType lambdaExpressionType) {
return true;
}
@Nullable
@Override
public Boolean visitArrayType(PsiArrayType arrayType) {
return arrayType.getComponentType().accept(this);
}
@Override
public Boolean visitType(PsiType type) {
return false;
}
private boolean check(PsiTypeParameter check) {
final PsiTypeParameterListOwner owner = check.getOwner();
if (owner == myMethod || owner == myClass) {
return true;
}
return false;
}
public boolean used(PsiTypeParameter... parameters) {
for (PsiTypeParameter parameter : parameters) {
if (myUsedTypeParams.contains(parameter)) return true;
}
return false;
}
}
}
@@ -216,7 +216,6 @@ public class LambdaCanBeReplacedWithAnonymousInspection extends BaseInspection {
}
final PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
if (functionalInterfaceType != null &&
LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType) &&
LambdaUtil.isFunctionalType(functionalInterfaceType)) {
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
if (interfaceMethod != null) {
@@ -67,8 +67,7 @@ public class LambdaParameterTypeCanBeSpecifiedInspection extends BaseInspection
}
final PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
if (functionalInterfaceType != null &&
LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null &&
LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType)) {
LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType) != null) {
final String inferredTypesText = LambdaRefactoringUtil.createLambdaParameterListWithFormalTypes(functionalInterfaceType, lambdaExpression,
true);
if (inferredTypesText != null) {
@@ -69,8 +69,7 @@ public class ExtractToMethodReferenceIntention extends BaseElementAtCaretIntenti
//is a valid lambda
PsiType functionalInterfaceType = lambdaExpression.getFunctionalInterfaceType();
if (functionalInterfaceType == null ||
LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType) == null ||
!LambdaUtil.isLambdaFullyInferred(lambdaExpression, functionalInterfaceType)) {
LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType) == null) {
return false;
}