mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
delete old inference strategy for java 8
This commit is contained in:
+12
-3
@@ -23,6 +23,7 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -57,7 +58,7 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti
|
||||
if (parameter.getTypeElement() == null) return false;
|
||||
}
|
||||
if (parameters.length == 0) return false;
|
||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, false);
|
||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, true);
|
||||
if (functionalInterfaceType != null) {
|
||||
final PsiElement lambdaParent = expression.getParent();
|
||||
if (lambdaParent instanceof PsiExpressionList) {
|
||||
@@ -84,11 +85,12 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti
|
||||
|
||||
for (PsiTypeParameter parameter : typeParameters) {
|
||||
final PsiType psiType = substitutor.substitute(parameter);
|
||||
if (psiType == null || LambdaUtil.dependsOnTypeParams(psiType, expression, parameter)) return false;
|
||||
if (psiType == null || dependsOnTypeParams(psiType, expression, parameter)) return false;
|
||||
}
|
||||
return functionalInterfaceType.isAssignableFrom(substitutor.substitute(method.getParameterList().getParameters()[idx].getType()));
|
||||
}
|
||||
}
|
||||
else if (!LambdaUtil.isLambdaFullyInferred(expression, functionalInterfaceType)) {
|
||||
if (!LambdaUtil.isLambdaFullyInferred(expression, functionalInterfaceType)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -122,4 +124,11 @@ public class RedundantLambdaParameterTypeIntention extends PsiElementBaseIntenti
|
||||
lambdaExpression.getParameterList().replace(expression.getParameterList());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,12 +239,6 @@ public class LambdaUtil {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static boolean dependsOnTypeParams(PsiType type,
|
||||
PsiLambdaExpression expr,
|
||||
PsiTypeParameter param2Check) {
|
||||
return depends(type, new TypeParamsChecker(expr), param2Check);
|
||||
}
|
||||
|
||||
public static boolean dependsOnTypeParams(PsiType type,
|
||||
PsiType functionalInterfaceType,
|
||||
PsiElement lambdaExpression,
|
||||
@@ -253,13 +247,7 @@ public class LambdaUtil {
|
||||
PsiUtil.resolveClassInType(functionalInterfaceType)), param2Check);
|
||||
}
|
||||
|
||||
public static boolean dependsOnTypeParams(PsiType type,
|
||||
PsiClass aClass,
|
||||
PsiMethod aMethod) {
|
||||
return depends(type, new TypeParamsChecker(aMethod, aClass));
|
||||
}
|
||||
|
||||
static boolean depends(PsiType type, TypeParamsChecker visitor, PsiTypeParameter... 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) {
|
||||
@@ -268,79 +256,8 @@ public class LambdaUtil {
|
||||
return accept != null && accept.booleanValue();
|
||||
}
|
||||
|
||||
public static boolean isFreeFromTypeInferenceArgs(final PsiParameter[] methodParameters,
|
||||
final PsiLambdaExpression lambdaExpression,
|
||||
final PsiExpression expression,
|
||||
final PsiSubstitutor subst,
|
||||
final PsiType functionalInterfaceType,
|
||||
final PsiTypeParameter typeParam) {
|
||||
if (expression instanceof PsiCallExpression && ((PsiCallExpression)expression).getTypeArguments().length > 0) return true;
|
||||
if (expression instanceof PsiNewExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)expression).getClassOrAnonymousClassReference();
|
||||
if (classReference != null) {
|
||||
final PsiReferenceParameterList parameterList = classReference.getParameterList();
|
||||
if (parameterList != null) {
|
||||
final PsiTypeElement[] typeParameterElements = parameterList.getTypeParameterElements();
|
||||
if (typeParameterElements.length > 0) {
|
||||
if (!(typeParameterElements[0].getType() instanceof PsiDiamondType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final PsiParameter[] lambdaParams = lambdaExpression.getParameterList().getParameters();
|
||||
if (lambdaParams.length != methodParameters.length) return false;
|
||||
final boolean[] independent = {true};
|
||||
final PsiMethod interfaceMethod = getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
if (interfaceMethod == null) return false;
|
||||
final TypeParamsChecker paramsChecker = new TypeParamsChecker(lambdaExpression);
|
||||
for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
|
||||
subst.substitute(parameter.getType()).accept(paramsChecker);
|
||||
}
|
||||
paramsChecker.myUsedTypeParams.add(typeParam);
|
||||
|
||||
expression.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitConditionalExpression(PsiConditionalExpression expression) {
|
||||
final PsiExpression thenExpression = expression.getThenExpression();
|
||||
if (thenExpression != null) {
|
||||
thenExpression.accept(this);
|
||||
}
|
||||
final PsiExpression elseExpression = expression.getElseExpression();
|
||||
if (elseExpression != null) {
|
||||
elseExpression.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
super.visitReferenceExpression(expression);
|
||||
int usedParamIdx = -1;
|
||||
for (int i = 0; i < lambdaParams.length; i++) {
|
||||
PsiParameter param = lambdaParams[i];
|
||||
if (expression.isReferenceTo(param)) {
|
||||
usedParamIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (usedParamIdx > -1 && dependsOnTypeParams(subst.substitute(methodParameters[usedParamIdx].getType()), functionalInterfaceType,
|
||||
lambdaExpression, paramsChecker.myUsedTypeParams.toArray(new PsiTypeParameter[paramsChecker.myUsedTypeParams.size()]))) {
|
||||
independent[0] = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return independent[0];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType getFunctionalInterfaceType(PsiElement expression, final boolean tryToSubstitute) {
|
||||
return getFunctionalInterfaceType(expression, tryToSubstitute, -1);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiType getFunctionalInterfaceType(PsiElement expression, final boolean tryToSubstitute, int paramIdx) {
|
||||
PsiElement parent = expression.getParent();
|
||||
PsiElement element = expression;
|
||||
while (parent instanceof PsiParenthesizedExpression || parent instanceof PsiConditionalExpression) {
|
||||
@@ -443,53 +360,6 @@ public class LambdaUtil {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static PsiType getLambdaParameterType(PsiParameter param) {
|
||||
final PsiElement paramParent = param.getParent();
|
||||
if (paramParent instanceof PsiParameterList) {
|
||||
final int parameterIndex = ((PsiParameterList)paramParent).getParameterIndex(param);
|
||||
if (parameterIndex > -1) {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
|
||||
if (lambdaExpression != null) {
|
||||
|
||||
PsiType type = getFunctionalInterfaceType(lambdaExpression, true, parameterIndex);
|
||||
if (type == null) {
|
||||
type = getFunctionalInterfaceType(lambdaExpression, false);
|
||||
}
|
||||
if (type instanceof PsiIntersectionType) {
|
||||
final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts();
|
||||
for (PsiType conjunct : conjuncts) {
|
||||
final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, conjunct);
|
||||
if (lambdaParameterFromType != null) return lambdaParameterFromType;
|
||||
}
|
||||
} else {
|
||||
final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, type);
|
||||
if (lambdaParameterFromType != null) {
|
||||
return lambdaParameterFromType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new PsiLambdaParameterType(param);
|
||||
}
|
||||
|
||||
private static PsiType getLambdaParameterFromType(int parameterIndex, PsiLambdaExpression lambdaExpression, PsiType conjunct) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(conjunct);
|
||||
if (resolveResult != null) {
|
||||
final PsiMethod method = getFunctionalInterfaceMethod(conjunct);
|
||||
if (method != null) {
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (parameterIndex < parameters.length) {
|
||||
final PsiType psiType = getSubstitutor(method, resolveResult).substitute(parameters[parameterIndex].getType());
|
||||
if (!dependsOnTypeParams(psiType, conjunct, lambdaExpression)) {
|
||||
return GenericsUtil.eliminateWildcards(psiType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean notInferredType(PsiType typeByExpression) {
|
||||
return typeByExpression instanceof PsiMethodReferenceType || typeByExpression instanceof PsiLambdaExpressionType || typeByExpression instanceof PsiLambdaParameterType;
|
||||
}
|
||||
@@ -560,19 +430,10 @@ public class LambdaUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
|
||||
public static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
|
||||
private PsiMethod myMethod;
|
||||
private final PsiClass myClass;
|
||||
private final Set<PsiTypeParameter> myUsedTypeParams = new HashSet<PsiTypeParameter>();
|
||||
|
||||
private TypeParamsChecker(PsiMethod method, PsiClass aClass) {
|
||||
myMethod = method;
|
||||
myClass = aClass;
|
||||
}
|
||||
|
||||
public TypeParamsChecker(PsiElement expression) {
|
||||
this(expression, PsiUtil.resolveGenericsClassInType(getFunctionalInterfaceType(expression, false)).getElement());
|
||||
}
|
||||
public final Set<PsiTypeParameter> myUsedTypeParams = new HashSet<PsiTypeParameter>();
|
||||
|
||||
public TypeParamsChecker(PsiElement expression, PsiClass aClass) {
|
||||
myClass = aClass;
|
||||
|
||||
@@ -1065,11 +1065,11 @@ public final class PsiUtil extends PsiUtilCore {
|
||||
return className + "." + member.getName();
|
||||
}
|
||||
|
||||
static boolean checkSameExpression(PsiExpression templateExpr, final PsiExpression expression) {
|
||||
static boolean checkSameExpression(PsiElement templateExpr, final PsiExpression expression) {
|
||||
return templateExpr.equals(skipParenthesizedExprDown(expression));
|
||||
}
|
||||
|
||||
public static boolean isCondition(PsiExpression expr, PsiElement parent) {
|
||||
public static boolean isCondition(PsiElement expr, PsiElement parent) {
|
||||
if (parent instanceof PsiIfStatement) {
|
||||
if (checkSameExpression(expr, ((PsiIfStatement)parent).getCondition())) {
|
||||
return true;
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.SearchScope;
|
||||
import com.intellij.psi.stubs.IStubElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.reference.SoftReference;
|
||||
import com.intellij.ui.RowIcon;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
@@ -59,6 +60,53 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
|
||||
super(node);
|
||||
}
|
||||
|
||||
public static PsiType getLambdaParameterType(PsiParameter param) {
|
||||
final PsiElement paramParent = param.getParent();
|
||||
if (paramParent instanceof PsiParameterList) {
|
||||
final int parameterIndex = ((PsiParameterList)paramParent).getParameterIndex(param);
|
||||
if (parameterIndex > -1) {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(param, PsiLambdaExpression.class);
|
||||
if (lambdaExpression != null) {
|
||||
|
||||
PsiType type = LambdaUtil.getFunctionalInterfaceType(lambdaExpression, true);
|
||||
if (type == null) {
|
||||
type = LambdaUtil.getFunctionalInterfaceType(lambdaExpression, false);
|
||||
}
|
||||
if (type instanceof PsiIntersectionType) {
|
||||
final PsiType[] conjuncts = ((PsiIntersectionType)type).getConjuncts();
|
||||
for (PsiType conjunct : conjuncts) {
|
||||
final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, conjunct);
|
||||
if (lambdaParameterFromType != null) return lambdaParameterFromType;
|
||||
}
|
||||
} else {
|
||||
final PsiType lambdaParameterFromType = getLambdaParameterFromType(parameterIndex, lambdaExpression, type);
|
||||
if (lambdaParameterFromType != null) {
|
||||
return lambdaParameterFromType;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new PsiLambdaParameterType(param);
|
||||
}
|
||||
|
||||
private static PsiType getLambdaParameterFromType(int parameterIndex, PsiLambdaExpression lambdaExpression, PsiType conjunct) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(conjunct);
|
||||
if (resolveResult != null) {
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(conjunct);
|
||||
if (method != null) {
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
if (parameterIndex < parameters.length) {
|
||||
final PsiType psiType = LambdaUtil.getSubstitutor(method, resolveResult).substitute(parameters[parameterIndex].getType());
|
||||
if (!LambdaUtil.dependsOnTypeParams(psiType, conjunct, lambdaExpression)) {
|
||||
return GenericsUtil.eliminateWildcards(psiType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void subtreeChanged() {
|
||||
super.subtreeChanged();
|
||||
@@ -138,7 +186,7 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
|
||||
PsiTypeElement typeElement = getTypeElement();
|
||||
if (typeElement == null) {
|
||||
assert isLambdaParameter() : this;
|
||||
return LambdaUtil.getLambdaParameterType(this);
|
||||
return getLambdaParameterType(this);
|
||||
}
|
||||
else {
|
||||
return JavaSharedImplUtil.getType(typeElement, getParameterIdentifier());
|
||||
|
||||
-114
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2013 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source.resolve;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.scope.MethodProcessorSetupFailedException;
|
||||
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
|
||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: 2/14/13
|
||||
*/
|
||||
public class GraphInferencePolicy extends ProcessCandidateParameterTypeInferencePolicy {
|
||||
private static final ThreadLocal<Map<PsiExpression, Map<JavaResolveResult, PsiSubstitutor>>> ourResults = new ThreadLocal<Map<PsiExpression, Map<JavaResolveResult, PsiSubstitutor>>>() {
|
||||
@Override
|
||||
protected Map<PsiExpression, Map<JavaResolveResult, PsiSubstitutor>> initialValue() {
|
||||
return new WeakHashMap<PsiExpression, Map<JavaResolveResult, PsiSubstitutor>>();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected List<PsiExpression> getExpressions(PsiExpression[] expressions, int i) {
|
||||
final List<PsiExpression> list = Arrays.asList(expressions);
|
||||
list.set(i, null);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiSubstitutor getSubstitutor(PsiCallExpression contextCall, PsiExpression[] expressions, int i, JavaResolveResult result) {
|
||||
Map<JavaResolveResult, PsiSubstitutor> map = ourResults.get().get(contextCall);
|
||||
if (map != null) {
|
||||
final PsiSubstitutor substitutor = map.get(result);
|
||||
if (substitutor != PsiSubstitutor.UNKNOWN && substitutor != null && substitutor.isValid()) return substitutor;
|
||||
}
|
||||
final PsiSubstitutor substitutor = super.getSubstitutor(contextCall, expressions, i, result);
|
||||
if (map != null) {
|
||||
map.put(result, substitutor);
|
||||
}
|
||||
return substitutor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JavaResolveResult[] getResults(@NotNull PsiCallExpression contextCall, final int exprIdx)
|
||||
throws MethodProcessorSetupFailedException {
|
||||
Map<JavaResolveResult, PsiSubstitutor> map = ourResults.get().get(contextCall);
|
||||
if (map != null) {
|
||||
final Set<JavaResolveResult> results = map.keySet();
|
||||
return results.toArray(new JavaResolveResult[results.size()]);
|
||||
}
|
||||
|
||||
PsiFile containingFile = contextCall.getContainingFile();
|
||||
final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(contextCall, containingFile) {
|
||||
@Override
|
||||
protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) {
|
||||
if (argumentList != null) {
|
||||
final PsiExpression[] expressions = argumentList.getExpressions();
|
||||
final PsiType[] types = PsiType.createArray(expressions.length);
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
if (i != exprIdx) {
|
||||
types[i] = expressions[i].getType();
|
||||
}
|
||||
else {
|
||||
types[i] = PsiType.NULL;
|
||||
}
|
||||
}
|
||||
return types;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
PsiScopesUtil.setupAndRunProcessor(processor, contextCall, false);
|
||||
final JavaResolveResult[] results = processor.getResult();
|
||||
|
||||
map = new WeakHashMap<JavaResolveResult, PsiSubstitutor>();
|
||||
ourResults.get().put(contextCall, map);
|
||||
for (JavaResolveResult result : results) {
|
||||
map.put(result, PsiSubstitutor.UNKNOWN);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public static void forget(PsiElement parent) {
|
||||
if (parent instanceof PsiExpression) {
|
||||
PsiElement gParent = PsiUtil.skipParenthesizedExprUp(parent.getParent());
|
||||
if (gParent instanceof PsiExpressionList) {
|
||||
final PsiElement ggParent = gParent.getParent();
|
||||
if (ggParent instanceof PsiCallExpression) {
|
||||
ourResults.get().remove(ggParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
-477
@@ -15,29 +15,22 @@
|
||||
*/
|
||||
package com.intellij.psi.impl.source.resolve;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion;
|
||||
import com.intellij.openapi.projectRoots.JavaVersionService;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.RecursionGuard;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
*/
|
||||
@@ -50,7 +43,7 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
myManager = manager;
|
||||
}
|
||||
|
||||
private Pair<PsiType, ConstraintType> inferTypeForMethodTypeParameterInner(@NotNull PsiTypeParameter typeParameter,
|
||||
private Pair<PsiType, ConstraintType> inferTypeForMethodTypeParameterInner(@NotNull PsiTypeParameter typeParameter,
|
||||
@NotNull PsiParameter[] parameters,
|
||||
@NotNull PsiExpression[] arguments,
|
||||
@NotNull PsiSubstitutor partialSubstitutor,
|
||||
@@ -98,10 +91,6 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
PsiType lowerBound = PsiType.NULL;
|
||||
PsiType upperBound = PsiType.NULL;
|
||||
if (paramTypes.length > 0) {
|
||||
sortLambdaExpressionsLast(paramTypes, argTypes);
|
||||
boolean rawType = false;
|
||||
boolean nullPassed = false;
|
||||
boolean lambdaRaw = false;
|
||||
for (int j = 0; j < argTypes.length; j++) {
|
||||
PsiType argumentType = argTypes[j];
|
||||
if (argumentType == null) continue;
|
||||
@@ -109,8 +98,6 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
|
||||
PsiType parameterType = paramTypes[j];
|
||||
if (parameterType == null) break;
|
||||
rawType |= parameterType instanceof PsiClassType && ((PsiClassType)parameterType).isRaw();
|
||||
nullPassed |= argumentType == PsiType.NULL;
|
||||
|
||||
if (parameterType instanceof PsiEllipsisType) {
|
||||
parameterType = ((PsiEllipsisType)parameterType).getComponentType();
|
||||
@@ -119,26 +106,8 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
}
|
||||
}
|
||||
final Pair<PsiType,ConstraintType> currentSubstitution;
|
||||
if (argumentType instanceof PsiLambdaExpressionType) {
|
||||
currentSubstitution = inferSubstitutionFromLambda(typeParameter, (PsiLambdaExpressionType)argumentType, lowerBound, partialSubstitutor);
|
||||
if (rawType) {
|
||||
if (currentSubstitution == FAILED_INFERENCE || currentSubstitution == null && lowerBound == PsiType.NULL) return RAW_INFERENCE;
|
||||
}
|
||||
if (nullPassed && currentSubstitution == null) return RAW_INFERENCE;
|
||||
if (currentSubstitution != null && currentSubstitution.first == null) {
|
||||
lambdaRaw = true;
|
||||
}
|
||||
if (currentSubstitution == null && lambdaRaw) {
|
||||
return new Pair<PsiType, ConstraintType>(PsiType.getJavaLangObject(myManager, typeParameter.getResolveScope()), ConstraintType.EQUALS);
|
||||
}
|
||||
} else if (argumentType instanceof PsiMethodReferenceType) {
|
||||
final PsiMethodReferenceExpression referenceExpression = ((PsiMethodReferenceType)argumentType).getExpression();
|
||||
currentSubstitution = inferConstraintFromFunctionalInterfaceMethod(typeParameter, referenceExpression, partialSubstitutor.substitute(parameterType), partialSubstitutor, policy);
|
||||
}
|
||||
else {
|
||||
currentSubstitution = getSubstitutionForTypeParameterConstraint(typeParameter, parameterType,
|
||||
argumentType, true, PsiUtil.getLanguageLevel(typeParameter));
|
||||
}
|
||||
currentSubstitution = getSubstitutionForTypeParameterConstraint(typeParameter, parameterType,
|
||||
argumentType, true, PsiUtil.getLanguageLevel(typeParameter));
|
||||
if (currentSubstitution == null) continue;
|
||||
if (currentSubstitution == FAILED_INFERENCE) {
|
||||
return getFailedInferenceConstraint(typeParameter);
|
||||
@@ -210,23 +179,6 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void sortLambdaExpressionsLast(@NotNull PsiType[] paramTypes, @NotNull PsiType[] argTypes) {
|
||||
for (int i = 0; i < argTypes.length; i++) {
|
||||
PsiType argType = argTypes[i];
|
||||
if ((argType instanceof PsiLambdaExpressionType || argType instanceof PsiMethodReferenceType) && i < argTypes.length - 1) {
|
||||
int k = i + 1;
|
||||
while((argTypes[k] instanceof PsiLambdaExpressionType || argTypes[k] instanceof PsiMethodReferenceType) && k < argTypes.length - 1) {
|
||||
k++;
|
||||
}
|
||||
if (!(argTypes[k] instanceof PsiLambdaExpressionType || argTypes[k] instanceof PsiMethodReferenceType)) {
|
||||
ArrayUtil.swap(paramTypes, i, k);
|
||||
ArrayUtil.swap(argTypes, i, k);
|
||||
i = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Pair<PsiType, ConstraintType> getFailedInferenceConstraint(@NotNull PsiTypeParameter typeParameter) {
|
||||
return new Pair<PsiType, ConstraintType>(JavaPsiFacade.getInstance(typeParameter.getProject()).getElementFactory().createType(typeParameter), ConstraintType.EQUALS);
|
||||
}
|
||||
@@ -321,41 +273,36 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = 0; i < typeParameters.length; i++) {
|
||||
PsiTypeParameter typeParameter = typeParameters[i];
|
||||
PsiType substitution = substitutions[i];
|
||||
if (substitution != null) continue;
|
||||
for (int i = 0; i < typeParameters.length; i++) {
|
||||
PsiTypeParameter typeParameter = typeParameters[i];
|
||||
PsiType substitution = substitutions[i];
|
||||
if (substitution != null) continue;
|
||||
|
||||
Pair<PsiType, ConstraintType> constraint = constraints[i];
|
||||
if (constraint == null) {
|
||||
constraint = inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, policy);
|
||||
}
|
||||
else if (constraint.getSecond() == ConstraintType.SUBTYPE) {
|
||||
Pair<PsiType, ConstraintType> otherConstraint =
|
||||
inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, policy);
|
||||
if (otherConstraint != null) {
|
||||
if (otherConstraint.getSecond() == ConstraintType.EQUALS || otherConstraint.getSecond() == ConstraintType.SUPERTYPE) {
|
||||
constraint = otherConstraint;
|
||||
}
|
||||
Pair<PsiType, ConstraintType> constraint = constraints[i];
|
||||
if (constraint == null) {
|
||||
constraint = inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, policy);
|
||||
}
|
||||
else if (constraint.getSecond() == ConstraintType.SUBTYPE) {
|
||||
Pair<PsiType, ConstraintType> otherConstraint =
|
||||
inferMethodTypeParameterFromParent(typeParameter, partialSubstitutor, parent, policy);
|
||||
if (otherConstraint != null) {
|
||||
if (otherConstraint.getSecond() == ConstraintType.EQUALS || otherConstraint.getSecond() == ConstraintType.SUPERTYPE) {
|
||||
constraint = otherConstraint;
|
||||
}
|
||||
}
|
||||
|
||||
if (constraint != null) {
|
||||
substitution = constraint.getFirst();
|
||||
}
|
||||
|
||||
if (substitution == null) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
|
||||
return factory.createRawSubstitutor(partialSubstitutor, typeParameters);
|
||||
}
|
||||
if (substitution != PsiType.NULL) {
|
||||
partialSubstitutor = partialSubstitutor.put(typeParameter, substitution);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
GraphInferencePolicy.forget(parent);
|
||||
|
||||
if (constraint != null) {
|
||||
substitution = constraint.getFirst();
|
||||
}
|
||||
|
||||
if (substitution == null) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
|
||||
return factory.createRawSubstitutor(partialSubstitutor, typeParameters);
|
||||
}
|
||||
if (substitution != PsiType.NULL) {
|
||||
partialSubstitutor = partialSubstitutor.put(typeParameter, substitution);
|
||||
}
|
||||
}
|
||||
return partialSubstitutor;
|
||||
}
|
||||
@@ -544,222 +491,6 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
return getSubstitutionForTypeParameterInner(param, arg, patternType, ConstraintType.SUPERTYPE, 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<PsiType, ConstraintType> inferSubstitutionFromLambda(PsiTypeParameter typeParam,
|
||||
PsiLambdaExpressionType arg,
|
||||
PsiType lowerBound,
|
||||
PsiSubstitutor partialSubstitutor) {
|
||||
final PsiLambdaExpression lambdaExpression = arg.getExpression();
|
||||
if (PsiUtil.getLanguageLevel(lambdaExpression).isAtLeast(LanguageLevel.JDK_1_8)) {
|
||||
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(lambdaExpression.getParent());
|
||||
if (parent instanceof PsiExpressionList) {
|
||||
final PsiExpressionList expressionList = (PsiExpressionList)parent;
|
||||
final Map<PsiElement, Pair<PsiMethod, PsiSubstitutor>> methodMap = MethodCandidateInfo.CURRENT_CANDIDATE.get();
|
||||
final Pair<PsiMethod, PsiSubstitutor> pair = methodMap != null ? methodMap.get(expressionList) : null;
|
||||
if (pair != null) {
|
||||
final int i = LambdaUtil.getLambdaIdx(expressionList, lambdaExpression);
|
||||
if (i < 0) return null;
|
||||
final PsiParameter[] parameters = pair.first.getParameterList().getParameters();
|
||||
if (parameters.length <= i) return null;
|
||||
final PsiSubstitutor combinedSubst = pair.second.putAll(partialSubstitutor);
|
||||
methodMap.put(expressionList, Pair.create(pair.first, combinedSubst));
|
||||
return inferConstraintFromFunctionalInterfaceMethod(typeParam, lambdaExpression, combinedSubst.substitute(parameters[i].getType()), lowerBound);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return inferConstraintFromFunctionalInterfaceMethod(typeParam, lambdaExpression,
|
||||
partialSubstitutor.substitute(lambdaExpression.getFunctionalInterfaceType()), lowerBound);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<PsiType, ConstraintType> inferConstraintFromFunctionalInterfaceMethod(final PsiTypeParameter typeParam,
|
||||
final PsiMethodReferenceExpression methodReferenceExpression,
|
||||
final PsiType functionalInterfaceType,
|
||||
final PsiSubstitutor partialSubstitutor,
|
||||
final ParameterTypeInferencePolicy policy) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final PsiMethod functionalInterfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
|
||||
if (functionalInterfaceMethod != null) {
|
||||
final PsiSubstitutor subst = LambdaUtil.getSubstitutor(functionalInterfaceMethod, resolveResult);
|
||||
final PsiParameter[] methodParameters = functionalInterfaceMethod.getParameterList().getParameters();
|
||||
PsiType[] methodParamTypes = PsiType.createArray(methodParameters.length);
|
||||
for (int i = 0; i < methodParameters.length; i++) {
|
||||
methodParamTypes[i] = GenericsUtil.eliminateWildcards(subst.substitute(methodParameters[i].getType()));
|
||||
}
|
||||
|
||||
if (methodParamsDependOn(typeParam, methodReferenceExpression, functionalInterfaceType, methodParameters, subst)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiType[] args = PsiType.createArray(methodParameters.length);
|
||||
Map<PsiMethodReferenceExpression,PsiType> map = PsiMethodReferenceUtil.ourRefs.get();
|
||||
if (map == null) {
|
||||
map = new HashMap<PsiMethodReferenceExpression, PsiType>();
|
||||
PsiMethodReferenceUtil.ourRefs.set(map);
|
||||
}
|
||||
final PsiType added = map.put(methodReferenceExpression, functionalInterfaceType);
|
||||
final JavaResolveResult methReferenceResolveResult;
|
||||
try {
|
||||
methReferenceResolveResult = methodReferenceExpression.advancedResolve(false);
|
||||
}
|
||||
finally {
|
||||
if (added == null) {
|
||||
map.remove(methodReferenceExpression);
|
||||
}
|
||||
}
|
||||
final PsiElement resolved = methReferenceResolveResult.getElement();
|
||||
if (resolved instanceof PsiMethod) {
|
||||
final PsiMethod method = (PsiMethod)resolved;
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
boolean hasReceiver = false;
|
||||
if (methodParamTypes.length == parameters.length + 1) {
|
||||
if (!PsiMethodReferenceUtil
|
||||
.isReceiverType(methodParamTypes[0], method.getContainingClass(), methReferenceResolveResult.getSubstitutor())) return null;
|
||||
hasReceiver = true;
|
||||
} else if (parameters.length != methodParameters.length) {
|
||||
return null;
|
||||
}
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
args[i] = methReferenceResolveResult.getSubstitutor().substitute(subst.substitute(parameters[i].getType()));
|
||||
}
|
||||
|
||||
final PsiType[] typesToInfer = hasReceiver ? ArrayUtil.remove(methodParamTypes, 0) : methodParamTypes;
|
||||
final Pair<PsiType, ConstraintType> constraint = inferTypeForMethodTypeParameterInner(typeParam, typesToInfer, args, subst, null, DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
if (constraint != null){
|
||||
return constraint;
|
||||
}
|
||||
PsiType functionalInterfaceReturnType = functionalInterfaceMethod.getReturnType();
|
||||
if (functionalInterfaceReturnType != null && functionalInterfaceReturnType != PsiType.VOID) {
|
||||
functionalInterfaceReturnType = GenericsUtil.eliminateWildcards(subst.substitute(functionalInterfaceReturnType));
|
||||
final PsiType argType;
|
||||
if (method.isConstructor()) {
|
||||
argType = JavaPsiFacade.getElementFactory(functionalInterfaceMethod.getProject()).createType(method.getContainingClass(), methReferenceResolveResult.getSubstitutor());
|
||||
} else {
|
||||
argType = methReferenceResolveResult.getSubstitutor().substitute(subst.substitute(method.getReturnType()));
|
||||
}
|
||||
final Pair<PsiType, ConstraintType> typeParameterConstraint =
|
||||
getSubstitutionForTypeParameterConstraint(typeParam, functionalInterfaceReturnType, argType, true, PsiUtil.getLanguageLevel(functionalInterfaceMethod));
|
||||
if (typeParameterConstraint != null && typeParameterConstraint.getSecond() != ConstraintType.EQUALS && method.isConstructor()) {
|
||||
final Pair<PsiType, ConstraintType> constraintFromParent =
|
||||
inferMethodTypeParameterFromParent(typeParam, partialSubstitutor, methodReferenceExpression.getParent().getParent(), policy);
|
||||
if (constraintFromParent != null && constraintFromParent.getSecond() == ConstraintType.EQUALS) return constraintFromParent;
|
||||
}
|
||||
return typeParameterConstraint;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<PsiType, ConstraintType> inferConstraintFromFunctionalInterfaceMethod(PsiTypeParameter typeParam,
|
||||
final PsiLambdaExpression lambdaExpression,
|
||||
final PsiType functionalInterfaceType,
|
||||
PsiType lowerBound) {
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
|
||||
if (method != null) {
|
||||
final PsiSubstitutor subst = LambdaUtil.getSubstitutor(method, resolveResult);
|
||||
final Pair<PsiType, ConstraintType> constraintFromFormalParams = inferConstraintFromLambdaFormalParams(typeParam, subst, method, lambdaExpression);
|
||||
if (constraintFromFormalParams != null) return constraintFromFormalParams;
|
||||
|
||||
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
|
||||
if (methodParamsDependOn(typeParam, lambdaExpression, functionalInterfaceType, methodParameters, subst)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiType returnType = subst.substitute(method.getReturnType());
|
||||
if (returnType != null && returnType != PsiType.VOID) {
|
||||
Pair<PsiType, ConstraintType> constraint = null;
|
||||
final List<PsiExpression> expressions = LambdaUtil.getReturnExpressions(lambdaExpression);
|
||||
for (final PsiExpression expression : expressions) {
|
||||
final boolean independent = lambdaExpression.hasFormalParameterTypes() || LambdaUtil.isFreeFromTypeInferenceArgs(methodParameters, lambdaExpression, expression, subst, functionalInterfaceType, typeParam);
|
||||
if (!independent) {
|
||||
if (lowerBound != PsiType.NULL) {
|
||||
return null;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (expression instanceof PsiReferenceExpression && ((PsiReferenceExpression)expression).resolve() == null) continue;
|
||||
PsiType exprType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, true, new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
return expression.getType();
|
||||
}
|
||||
});
|
||||
if (exprType instanceof PsiLambdaParameterType) {
|
||||
final PsiParameter parameter = ((PsiLambdaParameterType)exprType).getParameter();
|
||||
final int parameterIndex = lambdaExpression.getParameterList().getParameterIndex(parameter);
|
||||
if (parameterIndex > -1) {
|
||||
exprType = subst.substitute(methodParameters[parameterIndex].getType());
|
||||
}
|
||||
} else if (exprType instanceof PsiLambdaExpressionType) {
|
||||
return inferConstraintFromFunctionalInterfaceMethod(typeParam, ((PsiLambdaExpressionType)exprType).getExpression(), returnType,
|
||||
lowerBound);
|
||||
} else if (exprType == null && independent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (exprType == null){
|
||||
return FAILED_INFERENCE;
|
||||
}
|
||||
|
||||
final Pair<PsiType, ConstraintType> returnExprConstraint =
|
||||
getSubstitutionForTypeParameterConstraint(typeParam, GenericsUtil.eliminateWildcards(returnType), exprType, true, PsiUtil.getLanguageLevel(method));
|
||||
if (returnExprConstraint != null) {
|
||||
if (returnExprConstraint == FAILED_INFERENCE) return returnExprConstraint;
|
||||
if (constraint != null) {
|
||||
final PsiType leastUpperBound = GenericsUtil.getLeastUpperBound(constraint.getFirst(), returnExprConstraint.getFirst(), myManager);
|
||||
constraint = new Pair<PsiType, ConstraintType>(leastUpperBound, ConstraintType.SUPERTYPE);
|
||||
} else {
|
||||
constraint = returnExprConstraint;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (constraint != null) return constraint;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean methodParamsDependOn(PsiTypeParameter typeParam, PsiElement psiElement,
|
||||
PsiType functionalInterfaceType,
|
||||
PsiParameter[] methodParameters,
|
||||
PsiSubstitutor subst) {
|
||||
for (PsiParameter parameter : methodParameters) {
|
||||
if (LambdaUtil.dependsOnTypeParams(subst.substitute(parameter.getType()), functionalInterfaceType, psiElement, typeParam)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<PsiType, ConstraintType> inferConstraintFromLambdaFormalParams(PsiTypeParameter typeParam,
|
||||
PsiSubstitutor subst,
|
||||
PsiMethod method, PsiLambdaExpression lambdaExpression) {
|
||||
final PsiParameter[] parameters = lambdaExpression.getParameterList().getParameters();
|
||||
if (parameters.length == 0) return null;
|
||||
final PsiType[] lambdaArgs = PsiType.createArray(parameters.length);
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
PsiParameter parameter = parameters[i];
|
||||
if (parameter.getTypeElement() == null) {
|
||||
return null;
|
||||
}
|
||||
lambdaArgs[i] = parameter.getType();
|
||||
}
|
||||
|
||||
final PsiParameter[] methodParameters = method.getParameterList().getParameters();
|
||||
PsiType[] methodParamTypes = PsiType.createArray(methodParameters.length);
|
||||
for (int i = 0; i < methodParameters.length; i++) {
|
||||
methodParamTypes[i] = GenericsUtil.eliminateWildcards(subst.substitute(methodParameters[i].getType()));
|
||||
}
|
||||
return inferTypeForMethodTypeParameterInner(typeParam, methodParamTypes, lambdaArgs, subst, null, DefaultParameterTypeInferencePolicy.INSTANCE);
|
||||
}
|
||||
|
||||
private static PsiType intersectAllExtends(PsiTypeParameter typeParam, PsiType arg) {
|
||||
if (arg == null) return null;
|
||||
PsiClassType[] superTypes = typeParam.getSuperTypes();
|
||||
@@ -979,48 +710,10 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
PsiType expectedType = PsiTypesUtil.getExpectedTypeByParent(methodCall);
|
||||
|
||||
if (expectedType == null) {
|
||||
if (parent instanceof PsiReturnStatement) {
|
||||
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class);
|
||||
if (lambdaExpression != null) {
|
||||
return getFailedInferenceConstraint(typeParameter);
|
||||
}
|
||||
}
|
||||
else if (parent instanceof PsiExpressionList) {
|
||||
if (parent instanceof PsiExpressionList) {
|
||||
final PsiElement pParent = parent.getParent();
|
||||
if (pParent instanceof PsiCallExpression && parent.equals(((PsiCallExpression)pParent).getArgumentList())) {
|
||||
constraint = policy.inferTypeConstraintFromCallContext(methodCall, (PsiExpressionList)parent, (PsiCallExpression)pParent, typeParameter);
|
||||
if (constraint == null && PsiUtil.isLanguageLevel8OrHigher(methodCall)) {
|
||||
constraint = graphInferenceFromCallContext(methodCall, typeParameter, (PsiCallExpression)pParent);
|
||||
if (constraint != null) {
|
||||
final PsiType constraintFirst = constraint.getFirst();
|
||||
if (constraintFirst == null || constraintFirst.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
|
||||
constraint = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (parent instanceof PsiLambdaExpression) {
|
||||
expectedType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(methodCall, true, new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
return LambdaUtil.getFunctionalInterfaceReturnType(((PsiLambdaExpression)parent).getFunctionalInterfaceType());
|
||||
}
|
||||
});
|
||||
if (expectedType == null) {
|
||||
return null;
|
||||
}
|
||||
expectedType = GenericsUtil.eliminateWildcards(expectedType);
|
||||
} else if (parent instanceof PsiConditionalExpression) {
|
||||
if (PsiUtil.isLanguageLevel8OrHigher(parent)) {
|
||||
try {
|
||||
final Pair<PsiType, ConstraintType> pair = inferFromConditionalExpression(parent, methodCall, typeParameter, substitutor, policy);
|
||||
if (pair != null) {
|
||||
return pair;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
GraphInferencePolicy.forget(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1054,33 +747,6 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
|
||||
if (constraint == null) {
|
||||
if (methodCall instanceof PsiCallExpression) {
|
||||
final PsiExpressionList argumentList = ((PsiCallExpression)methodCall).getArgumentList();
|
||||
if (argumentList != null && PsiUtil.getLanguageLevel(argumentList).isAtLeast(LanguageLevel.JDK_1_8)) {
|
||||
for (PsiExpression expression : argumentList.getExpressions()) {
|
||||
if (expression instanceof PsiLambdaExpression || expression instanceof PsiMethodReferenceExpression) {
|
||||
final PsiType functionalInterfaceType = LambdaUtil.getFunctionalInterfaceType(expression, false);
|
||||
if (functionalInterfaceType == null || PsiUtil.resolveClassInType(functionalInterfaceType) == typeParameter){
|
||||
return getFailedInferenceConstraint(typeParameter);
|
||||
}
|
||||
final PsiMethod method = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
|
||||
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
|
||||
if (method == null || methodParamsDependOn(typeParameter, expression,
|
||||
functionalInterfaceType, method.getParameterList().getParameters(),
|
||||
LambdaUtil.getSubstitutor(method, resolveResult))) {
|
||||
if (expression instanceof PsiMethodReferenceExpression) {
|
||||
return getFailedInferenceConstraint(typeParameter);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
final Pair<PsiType, ConstraintType> inferredExceptionTypeConstraint = inferExceptionConstrains(typeParameter, expression, method, resolveResult.getSubstitutor());
|
||||
if (inferredExceptionTypeConstraint != null) {
|
||||
return inferredExceptionTypeConstraint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PsiType[] superTypes = typeParameter.getSuperTypes();
|
||||
if (superTypes.length == 0) return null;
|
||||
final PsiType[] types = PsiType.createArray(superTypes.length);
|
||||
@@ -1090,7 +756,6 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
superType = TypeConversionUtil.erasure(superType);
|
||||
}
|
||||
if (superType == null) superType = PsiType.getJavaLangObject(myManager, scope);
|
||||
if (superType == null) return null;
|
||||
types[i] = superType;
|
||||
}
|
||||
return policy.getInferredTypeWithNoConstraint(myManager, PsiIntersectionType.createIntersection(types));
|
||||
@@ -1120,113 +785,4 @@ public class PsiOldInferenceHelper implements PsiInferenceHelper {
|
||||
|
||||
return new Pair<PsiType, ConstraintType>(guess, constraint.getSecond());
|
||||
}
|
||||
|
||||
private static boolean checkSameExpression(PsiExpression templateExpr, final PsiExpression expression) {
|
||||
return templateExpr.equals(PsiUtil.skipParenthesizedExprDown(expression));
|
||||
}
|
||||
|
||||
private static Pair<PsiType, ConstraintType> inferExceptionConstrains(PsiTypeParameter typeParameter,
|
||||
PsiExpression expression,
|
||||
PsiMethod method,
|
||||
PsiSubstitutor substitutor) {
|
||||
final PsiClassType[] declaredExceptions = method.getThrowsList().getReferencedTypes();
|
||||
for (PsiClassType exception : declaredExceptions) {
|
||||
final PsiType substitute = substitutor.substitute(exception);
|
||||
if (PsiUtil.resolveClassInType(substitute) == typeParameter) {
|
||||
if (expression instanceof PsiLambdaExpression) {
|
||||
final PsiElement body = ((PsiLambdaExpression)expression).getBody();
|
||||
if (body != null) {
|
||||
final List<PsiClassType> unhandledExceptions = ExceptionUtil.getUnhandledExceptions(body);
|
||||
if (unhandledExceptions.isEmpty()) {
|
||||
return inferUncheckedException(typeParameter, exception, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (expression instanceof PsiMethodReferenceExpression) {
|
||||
final PsiElement resolve = ((PsiMethodReferenceExpression)expression).resolve();
|
||||
if (resolve instanceof PsiMethod) {
|
||||
final PsiClassType[] declaredThrowsList = ((PsiMethod)resolve).getThrowsList().getReferencedTypes();
|
||||
for (PsiClassType psiClassType : declaredThrowsList) {
|
||||
if (!ExceptionUtil.isUncheckedException(psiClassType)) return null;
|
||||
}
|
||||
return inferUncheckedException(typeParameter, exception, method);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Pair<PsiType, ConstraintType> inferUncheckedException(PsiTypeParameter typeParameter,
|
||||
PsiClassType exception,
|
||||
PsiMethod method) {
|
||||
final Project project = typeParameter.getProject();
|
||||
final PsiClass runtimeException = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_RUNTIME_EXCEPTION, method.getResolveScope());
|
||||
if (runtimeException != null) {
|
||||
for (PsiType superType : exception.getSuperTypes()) {
|
||||
if (!InheritanceUtil.isInheritorOrSelf(runtimeException, PsiUtil.resolveClassInType(superType), true)) {
|
||||
return getFailedInferenceConstraint(typeParameter);
|
||||
}
|
||||
}
|
||||
return Pair.<PsiType, ConstraintType>create(JavaPsiFacade.getElementFactory(project).createType(runtimeException, PsiSubstitutor.EMPTY), ConstraintType.EQUALS);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Pair<PsiType, ConstraintType> inferFromConditionalExpression(@NotNull PsiElement parent,
|
||||
@NotNull PsiExpression methodCall,
|
||||
@NotNull PsiTypeParameter typeParameter,
|
||||
@NotNull PsiSubstitutor substitutor,
|
||||
@NotNull ParameterTypeInferencePolicy policy) {
|
||||
Pair<PsiType, ConstraintType> pair =
|
||||
inferMethodTypeParameterFromParent(PsiUtil.skipParenthesizedExprUp(parent.getParent()), (PsiExpression)parent, typeParameter, substitutor, policy);
|
||||
if (pair == null) {
|
||||
final PsiExpression thenExpression = ((PsiConditionalExpression)parent).getThenExpression();
|
||||
final PsiExpression elseExpression = ((PsiConditionalExpression)parent).getElseExpression();
|
||||
final PsiType[] paramTypes = {((PsiMethod)typeParameter.getOwner()).getReturnType()};
|
||||
if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(elseExpression)) && thenExpression != null) {
|
||||
final PsiType thenType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(parent, true, new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
return thenExpression.getType();
|
||||
}
|
||||
});
|
||||
if (thenType != null) {
|
||||
pair = inferTypeForMethodTypeParameterInner(typeParameter, paramTypes, new PsiType[] {thenType}, substitutor, null, policy);
|
||||
}
|
||||
} else if (methodCall.equals(PsiUtil.skipParenthesizedExprDown(thenExpression)) && elseExpression != null) {
|
||||
final PsiType elseType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(parent, true, new Computable<PsiType>() {
|
||||
@Override
|
||||
public PsiType compute() {
|
||||
return elseExpression.getType();
|
||||
}
|
||||
});
|
||||
if (elseType != null) {
|
||||
pair = inferTypeForMethodTypeParameterInner(typeParameter, paramTypes, new PsiType[] {elseType}, substitutor, null, policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pair;
|
||||
}
|
||||
|
||||
private static final ProcessCandidateParameterTypeInferencePolicy GRAPH_INFERENCE_POLICY = new GraphInferencePolicy();
|
||||
|
||||
private static Pair<PsiType, ConstraintType> graphInferenceFromCallContext(@NotNull final PsiExpression methodCall,
|
||||
@NotNull final PsiTypeParameter typeParameter,
|
||||
@NotNull final PsiCallExpression parentCall) {
|
||||
if (Registry.is("disable.graph.inference", false)) return null;
|
||||
final PsiExpressionList argumentList = parentCall.getArgumentList();
|
||||
if (PsiDiamondType.ourDiamondGuard.currentStack().contains(parentCall)) {
|
||||
PsiDiamondType.ourDiamondGuard.prohibitResultCaching(parentCall);
|
||||
return FAILED_INFERENCE;
|
||||
}
|
||||
return PsiResolveHelper.ourGraphGuard.doPreventingRecursion(methodCall, true, new Computable<Pair<PsiType, ConstraintType>>() {
|
||||
@Override
|
||||
public Pair<PsiType, ConstraintType> compute() {
|
||||
return GRAPH_INFERENCE_POLICY.inferTypeConstraintFromCallContext(methodCall, argumentList, parentCall, typeParameter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -17,7 +17,6 @@ package com.intellij.psi.impl.source.resolve;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.graphInference.PsiGraphInferenceHelper;
|
||||
@@ -26,7 +25,8 @@ import com.intellij.psi.scope.MethodProcessorSetupFailedException;
|
||||
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
|
||||
import com.intellij.psi.scope.processor.MethodResolverProcessor;
|
||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -204,10 +204,10 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
|
||||
}
|
||||
|
||||
public PsiInferenceHelper getInferenceHelper(LanguageLevel languageLevel) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return myTestHelper != null ? myTestHelper : new PsiOldInferenceHelper(myManager);
|
||||
if (ApplicationManager.getApplication().isUnitTestMode() && myTestHelper != null) {
|
||||
return myTestHelper;
|
||||
}
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && Registry.is("enable.graph.inference", true)) {
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
|
||||
return new PsiGraphInferenceHelper(myManager);
|
||||
}
|
||||
return new PsiOldInferenceHelper(myManager);
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
class Test {
|
||||
void foo() {
|
||||
final Foo<Number> a = new Foo<Number>(1);
|
||||
final Foo<Number> a = new Foo<>(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ interface SAM<X> {
|
||||
|
||||
class Foo {
|
||||
void test() {
|
||||
SAM<String> c = (i, j) -> "" + i + j;
|
||||
SAM<X> c = (i, j) -> "" + i + j;
|
||||
SAM<Integer> s3 = m(c);
|
||||
}
|
||||
<X> SAM<X> m(SAM<X> s) { return null; }
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.intellij.codeInspection.compiler.JavacQuirksInspection;
|
||||
import com.intellij.codeInspection.redundantCast.RedundantCastInspection;
|
||||
import com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection;
|
||||
import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -52,4 +53,9 @@ public class AmbiguousMethodCallTest extends LightDaemonAnalyzerTestCase {
|
||||
public void testMultipleInheritance() throws Exception {
|
||||
doTest(false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LanguageLevel getLanguageLevel() {
|
||||
return LanguageLevel.JDK_1_7;
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -1,5 +1,7 @@
|
||||
package com.intellij.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
|
||||
public class RemoveRedundantArgumentTest extends LightQuickFixParameterizedTestCase {
|
||||
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
@@ -9,4 +11,8 @@ public class RemoveRedundantArgumentTest extends LightQuickFixParameterizedTestC
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/removeRedundantArgument";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LanguageLevel getLanguageLevel() {
|
||||
return LanguageLevel.JDK_1_7;
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.daemon.quickFix;
|
||||
|
||||
import com.intellij.codeInspection.ExplicitTypeCanBeDiamondInspection;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
@@ -37,4 +38,8 @@ public class Simplify2DiamondInspectionsTest extends LightQuickFixParameterizedT
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/explicit2diamond";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LanguageLevel getLanguageLevel() {
|
||||
return LanguageLevel.JDK_1_7;
|
||||
}
|
||||
}
|
||||
+6
@@ -16,6 +16,8 @@
|
||||
package com.intellij.codeInsight.daemon.quickFix;
|
||||
|
||||
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
|
||||
public class VariableTypeFromCallTest extends LightQuickFixParameterizedTestCase {
|
||||
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
@@ -25,5 +27,9 @@ public class VariableTypeFromCallTest extends LightQuickFixParameterizedTestCase
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/varTypeFromCall";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LanguageLevel getLanguageLevel() {
|
||||
return LanguageLevel.JDK_1_7;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -463,4 +463,9 @@ public class IntroduceParameterTest extends LightRefactoringTestCase {
|
||||
IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_INACCESSIBLE,
|
||||
declareFinal, false, null, parametersToRemove).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LanguageLevel getLanguageLevel() {
|
||||
return LanguageLevel.JDK_1_7;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,6 +428,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
|
||||
public void testLambdaExpr() throws Exception {
|
||||
|
||||
doTest(new MockIntroduceVariableHandler("c", false, false, false, "SAM<java.lang.Integer>"));
|
||||
}
|
||||
|
||||
@@ -436,7 +437,7 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
|
||||
public void testLambdaExprNotAccepted() throws Exception {
|
||||
doTest(new MockIntroduceVariableHandler("c", false, false, false, "SAM<java.lang.String>"));
|
||||
doTest(new MockIntroduceVariableHandler("c", false, false, false, "SAM<X>"));
|
||||
}
|
||||
|
||||
public void testOneLineLambdaVoidCompatible() throws Exception {
|
||||
|
||||
@@ -318,8 +318,6 @@ diagrams.rendering.no.cache=true
|
||||
|
||||
wolf.the.problem.solver=true
|
||||
ui.no.bangs.and.whistles=false
|
||||
disable.graph.inference=false
|
||||
enable.graph.inference=true
|
||||
|
||||
comment.by.line.bulk.lines.trigger=100
|
||||
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@ class Test2 {
|
||||
static <T> I<T> bar(I<T> i){return i;}
|
||||
|
||||
{
|
||||
bar(new I() {
|
||||
bar(new I<Object>() {
|
||||
@Override
|
||||
public Object foo(Y x) {
|
||||
public Object foo(Y<Object> x) {
|
||||
<selection>return x;</selection>
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user