method refs: use one thread local for all functional expressions

This commit is contained in:
Anna Kozlova
2014-11-27 10:58:57 +01:00
parent 552198fb47
commit cbb5c09d41
10 changed files with 35 additions and 64 deletions
@@ -101,7 +101,7 @@ public class LambdaCanBeMethodReferenceInspection extends BaseJavaBatchLocalInsp
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(callExpression.getProject());
final PsiMethodReferenceExpression methodReferenceExpression =
(PsiMethodReferenceExpression)elementFactory.createExpressionFromText(methodReferenceText, callExpression);
final Map<PsiMethodReferenceExpression, PsiType> map = PsiMethodReferenceUtil.getFunctionalTypeMap();
final Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap();
try {
map.put(methodReferenceExpression, functionalInterfaceType);
final JavaResolveResult result = methodReferenceExpression.advancedResolve(false);
@@ -50,9 +50,8 @@ public class MethodReferenceCompletionProvider extends CompletionProvider<Comple
final PsiElement position = parameters.getPosition();
final PsiElement refPlace = position.getParent();
final ExpectedTypeInfoImpl typeInfo =
new ExpectedTypeInfoImpl(returnType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, returnType, TailType.UNKNOWN, null,
ExpectedTypeInfoImpl.NULL);
final Map<PsiMethodReferenceExpression, PsiType> map = PsiMethodReferenceUtil.getFunctionalTypeMap();
new ExpectedTypeInfoImpl(returnType, ExpectedTypeInfo.TYPE_OR_SUBTYPE, returnType, TailType.UNKNOWN, null, ExpectedTypeInfoImpl.NULL);
final Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap();
Consumer<LookupElement> noTypeCheck = new Consumer<LookupElement>() {
@Override
public void consume(final LookupElement lookupElement) {
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.registry.Registry;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.*;
import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -286,6 +287,15 @@ public class LambdaUtil {
element = parent;
parent = parent.getParent();
}
final Map<PsiElement, PsiType> map = ourFunctionTypes.get();
if (map != null) {
final PsiType type = map.get(expression);
if (type != null) {
return type;
}
}
if (parent instanceof PsiArrayInitializerExpression) {
final PsiType psiType = ((PsiArrayInitializerExpression)parent).getType();
if (psiType instanceof PsiArrayType) {
@@ -327,13 +337,6 @@ public class LambdaUtil {
return properties.getSubstitutor().substitute(getNormalizedType(parameters[finalLambdaIdx]));
}
}
final Map<PsiElement, PsiType> map = ourFunctionTypes.get();
if (map != null) {
final PsiType type = map.get(expression);
if (type != null) {
return type;
}
}
final JavaResolveResult resolveResult = contextCall.resolveMethodGenerics();
final PsiElement resolve = resolveResult.getElement();
if (resolve instanceof PsiMethod) {
@@ -518,7 +521,17 @@ public class LambdaUtil {
}
return false;
}
@NotNull
public static Map<PsiElement, PsiType> getFunctionalTypeMap() {
Map<PsiElement, PsiType> map = ourFunctionTypes.get();
if (map == null) {
map = new HashMap<PsiElement, PsiType>();
ourFunctionTypes.set(map);
}
return map;
}
public static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
private PsiMethod myMethod;
private final PsiClass myClass;
@@ -27,8 +27,6 @@ import java.util.Map;
* User: anna
*/
public class PsiMethodReferenceUtil {
public static ThreadLocal<Map<PsiMethodReferenceExpression, PsiType>> ourRefs = new ThreadLocal<Map<PsiMethodReferenceExpression, PsiType>>();
public static final Logger LOG = Logger.getInstance("#" + PsiMethodReferenceUtil.class.getName());
public static boolean hasReceiver(PsiType[] parameterTypes, QualifierResolveResult qualifierResolveResult, PsiMethodReferenceExpression methodRef) {
@@ -97,16 +95,6 @@ public class PsiMethodReferenceUtil {
return !varargs || parameterTypes.length - 1 <= argTypes.length - offset;
}
@NotNull
public static Map<PsiMethodReferenceExpression, PsiType> getFunctionalTypeMap() {
Map<PsiMethodReferenceExpression, PsiType> map = ourRefs.get();
if (map == null) {
map = new HashMap<PsiMethodReferenceExpression, PsiType>();
ourRefs.set(map);
}
return map;
}
public static class QualifierResolveResult {
private final PsiClass myContainingClass;
private final PsiSubstitutor mySubstitutor;
@@ -746,8 +746,8 @@ public class PsiImplUtil {
return JavaResolveResult.EMPTY_ARRAY;
}
if (element instanceof PsiMethodReferenceExpression) {
// method refs: do not cache results during parent conflict resolving
final Map<PsiMethodReferenceExpression, PsiType> map = PsiMethodReferenceUtil.ourRefs.get();
// method refs: do not cache results during parent conflict resolving, acceptable checks, etc
final Map<PsiElement, PsiType> map = LambdaUtil.ourFunctionTypes.get();
if (map != null && map.containsKey(element)) {
return (JavaResolveResult[])resolver.resolve(element, psiFile, incompleteCode);
}
@@ -112,12 +112,7 @@ public abstract class InputOutputConstraintFormula implements ConstraintFormula
public void apply(PsiSubstitutor substitutor, boolean cache) {
setT(substitutor.substitute(getT()));
if (cache) {
Map<PsiElement, PsiType> map = LambdaUtil.ourFunctionTypes.get();
if (map == null) {
map = new HashMap<PsiElement, PsiType>();
LambdaUtil.ourFunctionTypes.set(map);
}
map.put(getExpression(), getT());
LambdaUtil.getFunctionalTypeMap().put(getExpression(), getT());
}
}
@@ -21,7 +21,6 @@ import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfacePa
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -124,7 +123,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
return true;
}
final Map<PsiMethodReferenceExpression, PsiType> map = PsiMethodReferenceUtil.getFunctionalTypeMap();
final Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap();
final PsiType added = map.put(myExpression, session.startWithFreshVars(groundTargetType));
final JavaResolveResult resolve;
try {
@@ -174,17 +174,7 @@ public class MethodReferenceResolver implements ResolveCache.PolyVariantContextR
}
protected PsiType getInterfaceType(PsiMethodReferenceExpression reference) {
PsiType functionalInterfaceType = null;
final Map<PsiMethodReferenceExpression,PsiType> map = PsiMethodReferenceUtil.ourRefs.get();
if (map != null) {
functionalInterfaceType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(map.get(reference));
}
if (functionalInterfaceType == null) {
functionalInterfaceType = reference.getFunctionalInterfaceType();
}
return functionalInterfaceType;
return reference.getFunctionalInterfaceType();
}
protected PsiConflictResolver createResolver(PsiMethodReferenceExpressionImpl referenceExpression,
@@ -181,11 +181,6 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
leftType = FunctionalInterfaceParameterizationUtil.getGroundTargetType(leftType, this);
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(leftType);
final PsiClass psiClass = resolveResult.getElement();
if (psiClass instanceof PsiAnonymousClass) {
return isAcceptable(((PsiAnonymousClass)psiClass).getBaseClassType());
}
if (MethodCandidateInfo.ourOverloadGuard.currentStack().contains(argsList)) {
final MethodCandidateInfo.CurrentCandidateProperties candidateProperties = MethodCandidateInfo.getCurrentMethod(argsList);
if (candidateProperties != null) {
@@ -200,13 +195,6 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
}
}
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
if (interfaceMethod == null) return false;
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult);
assert leftType != null;
if (!isPotentiallyCompatible(leftType)) {
return false;
}
@@ -215,7 +203,10 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
return true;
}
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
if (interfaceMethod == null) return false;
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult);
if (hasFormalParameterTypes()) {
final PsiParameter[] lambdaParameters = getParameterList().getParameters();
@@ -235,11 +226,7 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
PsiType methodReturnType = interfaceMethod.getReturnType();
if (methodReturnType != null && methodReturnType != PsiType.VOID) {
Map<PsiElement, PsiType> map = LambdaUtil.ourFunctionTypes.get();
if (map == null) {
map = new HashMap<PsiElement, PsiType>();
LambdaUtil.ourFunctionTypes.set(map);
}
Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap();
try {
if (map.put(this, leftType) != null) {
return false;
@@ -409,7 +409,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
// the result of applying capture conversion (5.1.10) to the return type of the invocation type (15.12.2.6) of the chosen declaration is R',
// where R is the target type that may be used to infer R'; neither R nor R' is void; and R' is compatible with R in an assignment context.
Map<PsiMethodReferenceExpression, PsiType> map = PsiMethodReferenceUtil.getFunctionalTypeMap();
Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap();
final JavaResolveResult result;
try {
if (map.put(this, left) != null) {