new inference: more precise potentially applicable method detection

This commit is contained in:
anna
2013-09-30 19:45:39 +02:00
parent a2f6e6560e
commit dfedfd420f
2 changed files with 75 additions and 17 deletions
@@ -19,6 +19,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
import com.intellij.psi.impl.source.tree.java.PsiMethodReferenceExpressionImpl;
import com.intellij.psi.util.PsiUtil;
import java.util.Arrays;
@@ -50,13 +51,51 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
}
final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, PsiUtil.resolveGenericsClassInType(myT));
final PsiParameter[] targetParameters = interfaceMethod.getParameterList().getParameters();
final PsiType returnType = substitutor.substitute(interfaceMethod.getReturnType());
LOG.assertTrue(returnType != null, interfaceMethod);
if (!myExpression.isExact()) {
final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters();
for (PsiParameter parameter : parameters) {
for (PsiParameter parameter : targetParameters) {
if (!session.isProperType(substitutor.substitute(parameter.getType()))) {
return false;
}
}
} else {
final PsiSubstitutor psiSubstitutor = PsiMethodReferenceUtil.getQualifierResolveResult(myExpression).getSubstitutor();
final PsiMethod applicableMethod = ((PsiMethodReferenceExpressionImpl)myExpression).getPotentiallyApplicableMethod();
LOG.assertTrue(applicableMethod != null);
final PsiParameter[] parameters = applicableMethod.getParameterList().getParameters();
if (targetParameters.length == parameters.length + 1) {
final PsiTypeElement qualifierTypeElement = myExpression.getQualifierType();
final PsiExpression qualifierExpression = myExpression.getQualifierExpression();
final PsiType qualifierType;
if (qualifierTypeElement != null) {
qualifierType = qualifierTypeElement.getType();
}
else {
LOG.assertTrue(qualifierExpression != null);
qualifierType = qualifierExpression.getType();
}
constraints.add(new SubtypingConstraint(qualifierType, substitutor.substitute(targetParameters[0].getType()), true));
for (int i = 1; i < targetParameters.length; i++) {
constraints.add(new TypeCompatibilityConstraint(psiSubstitutor.substitute(parameters[i - 1].getType()), substitutor.substitute(targetParameters[i].getType())));
}
} else {
for (int i = 0; i < targetParameters.length; i++) {
constraints.add(new TypeCompatibilityConstraint(psiSubstitutor.substitute(parameters[i].getType()), substitutor.substitute(targetParameters[i].getType())));
}
}
if (returnType != PsiType.VOID) {
final PsiType applicableMethodReturnType = applicableMethod.getReturnType();
if (applicableMethodReturnType == PsiType.VOID) {
return false;
}
if (applicableMethodReturnType != null) {
constraints.add(new TypeCompatibilityConstraint(returnType, psiSubstitutor.substitute(applicableMethodReturnType)));
}
}
return true;
}
final PsiElement resolve = myExpression.resolve();
@@ -64,8 +103,6 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
return false;
}
final PsiType returnType = interfaceMethod.getReturnType();
LOG.assertTrue(returnType != null, interfaceMethod);
if (PsiType.VOID.equals(returnType)) {
return true;
}
@@ -94,7 +131,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
return false;
}
constraints.add(new TypeCompatibilityConstraint(substitutor.substitute(returnType), referencedMethodReturnType));
constraints.add(new TypeCompatibilityConstraint(returnType, referencedMethodReturnType));
}
return true;
@@ -73,20 +73,41 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
@Override
public boolean isExact() {
PsiElement resolve = resolve();
if (resolve instanceof PsiMethod) {
if (!((PsiMethod)resolve).isVarArgs()) {
if (((PsiMethod)resolve).getTypeParameters().length > 0) {
final PsiReferenceParameterList parameterList = getParameterList();
return parameterList != null && parameterList.getTypeParameterElements().length > 0;
}
return true;
}
return false;
}
return resolve != null;
return getPotentiallyApplicableMethod() != null;
}
public PsiMethod getPotentiallyApplicableMethod() {
final PsiElement element = getReferenceNameElement();
final PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult = PsiMethodReferenceUtil.getQualifierResolveResult(this);
final PsiClass containingClass = qualifierResolveResult.getContainingClass();
if (containingClass != null) {
PsiMethod[] methods = null;
if (element instanceof PsiIdentifier) {
methods = containingClass.findMethodsByName(element.getText(), false);
}
else if (element instanceof PsiKeyword && PsiKeyword.NEW.equals(element.getText())) {
methods = containingClass.getConstructors();
}
if (methods != null) {
PsiMethod psiMethod = null;
for (PsiMethod method : methods) {
if (PsiUtil.isAccessible(method, this, null)) {
if (psiMethod != null) return null;
psiMethod = method;
}
}
if (psiMethod == null) return null;
if (psiMethod.isVarArgs()) return null;
if (psiMethod.getTypeParameters().length > 0) {
final PsiReferenceParameterList parameterList = getParameterList();
return parameterList != null && parameterList.getTypeParameterElements().length > 0 ? psiMethod : null;
}
return psiMethod;
}
}
return null;
}
@Override
public PsiExpression getQualifierExpression() {
final PsiElement qualifier = getQualifier();