diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java index 5b37bee0017e..8e6dfb6605f6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -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; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index c8e6d23c1feb..a49ef951572e 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -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();