overload resolution: same signatures should not check return types, etc already processed in hierarchical signatures (IDEA-172129)

This commit is contained in:
Anna.Kozlova
2017-04-28 20:04:34 +02:00
parent ee750f165b
commit b893701408
3 changed files with 15 additions and 83 deletions

View File

@@ -22,7 +22,6 @@ import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.Comparing;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil;
@@ -240,8 +239,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
}
}
nextConflict:
for (int i=0; i<conflicts.size();i++) {
for (int i = 0; i < conflicts.size(); i++) {
ProgressManager.checkCanceled();
CandidateInfo info = conflicts.get(i);
PsiMethod method = (PsiMethod)info.getElement();
@@ -267,7 +265,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
if (class1.isInterface() && CommonClassNames.JAVA_LANG_OBJECT.equals(existingClass.getQualifiedName())) {
signatures.put(signature, info);
continue;
}
}
else if (existingClass.isInterface() && CommonClassNames.JAVA_LANG_OBJECT.equals(class1.getQualifiedName())) {
conflicts.remove(info);
i--;
@@ -282,85 +280,6 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
PsiTreeUtil.isAncestor(scope1, scope2, true) &&
!existing.isAccessible()) { //prefer methods from outer class to inaccessible base class methods
signatures.put(signature, info);
continue;
}
}
// filter out methods with incorrect inferred bounds (for unrelated methods only)
boolean existingTypeParamAgree = areTypeParametersAgree(existing);
boolean infoTypeParamAgree = areTypeParametersAgree(info);
if (existingTypeParamAgree && !infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(method, existingMethod)) {
conflicts.remove(i);
i--;
continue;
}
if (!existingTypeParamAgree && infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) {
signatures.put(signature, info);
int index = conflicts.indexOf(existing);
conflicts.remove(index);
i--;
continue;
}
if (InheritanceUtil.isInheritorOrSelf(class1, existingClass, true) ||
InheritanceUtil.isInheritorOrSelf(existingClass, class1, true)) {
PsiParameter[] parameters = method.getParameterList().getParameters();
final PsiParameter[] existingParameters = existingMethod.getParameterList().getParameters();
for (int i1 = 0, parametersLength = parameters.length; i1 < parametersLength; i1++) {
if (parameters[i1].getType() instanceof PsiArrayType &&
!(existingParameters[i1].getType() instanceof PsiArrayType)) {//prefer more specific type
signatures.put(signature, info);
continue nextConflict;
}
}
PsiType returnType1 = method.getReturnType();
PsiType returnType2 = existingMethod.getReturnType();
if (returnType1 != null && returnType2 != null) {
returnType1 = infoSubstitutor.substitute(returnType1);
returnType2 = getSubstitutor((MethodCandidateInfo)existing, map).substitute(returnType2);
if (!returnType1.equals(returnType2) && returnType1.isAssignableFrom(returnType2)) {
conflicts.remove(i);
i--;
continue;
}
}
// prefer derived class
signatures.put(signature, info);
}
else {
final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(myArgumentsList, PsiMethodCallExpression.class);
if (methodCallExpression != null) {
final PsiReferenceExpression expression = methodCallExpression.getMethodExpression();
final PsiExpression qualifierExpression = expression.getQualifierExpression();
PsiClass currentClass;
if (qualifierExpression != null) {
currentClass = PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType());
}
else {
currentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
}
if (currentClass != null && existingClass != null && class1 != null) {
final PsiSubstitutor eSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(existingClass, currentClass, PsiSubstitutor.EMPTY, null);
final PsiSubstitutor cSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(class1, currentClass, PsiSubstitutor.EMPTY, null);
if (eSubstitutor != null && cSubstitutor != null &&
MethodSignatureUtil.areSignaturesEqual(existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) {
final PsiType returnType = eSubstitutor.substitute(existingMethod.getReturnType());
final PsiType returnType1 = cSubstitutor.substitute(method.getReturnType());
if (returnType != null && returnType1 != null && !returnType1.equals(returnType)) {
if (TypeConversionUtil.isAssignable(returnType, returnType1, false)) {
if (class1.isInterface() && !existingClass.isInterface()) continue;
conflicts.remove(existing);
} else {
if (!TypeConversionUtil.isAssignable(returnType1, returnType, false)) continue;
conflicts.remove(i);
}
i--;
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
import java.util.function.Consumer;
class Foo {
private static Consumer<Object> consumer = Foo::vaMethod;
private static <T> T vaMethod(Object... varargs) {
return null;
}
}

View File

@@ -252,6 +252,11 @@ public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase {
doTest(false);
}
public void testDontSkipInapplicableMethodsDuringSameSignatureCheck() throws Exception {
doTest(false);
}
private void doTest() {
doTest(true);
}