moreSpecific: use site info to check assignability, prefer concrete to abstract methods (IDEA-57569)

This commit is contained in:
Anna Kozlova
2013-08-15 13:49:57 +04:00
parent 5b6fe03a18
commit 230c6fd84b
6 changed files with 80 additions and 17 deletions
@@ -94,6 +94,10 @@ public class MethodCandidateInfo extends CandidateInfo{
return myApplicabilityLevel;
}
public PsiSubstitutor getSiteSubstitutor() {
return super.getSubstitutor();
}
@Override
public PsiSubstitutor getSubstitutor() {
if (myCalcedSubstitutor == null) {
@@ -17,6 +17,7 @@ package com.intellij.psi.scope.conflictResolvers;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.Comparing;
@@ -39,8 +40,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.sun.tools.javac.code.Flags.ABSTRACT;
/**
* Created by IntelliJ IDEA.
* User: ik
@@ -502,15 +501,21 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
if (boxingHappened[0] > 0 && boxingHappened[1] == 0) return Specifics.SECOND;
if (sameBoxing) {
final PsiResolveHelper resolveHelper = PsiResolveHelper.SERVICE.getInstance(myArgumentsList.getProject());
int level1 = getLevel(applicabilityLevel, languageLevel, method1, typeParameters1, types2, types1, resolveHelper);
int level2 = getLevel(applicabilityLevel, languageLevel, method2, typeParameters2, types1, types2, resolveHelper);
final PsiSubstitutor siteSubstitutor1 = ((MethodCandidateInfo)info1).getSiteSubstitutor();
final PsiSubstitutor siteSubstitutor2 = ((MethodCandidateInfo)info2).getSiteSubstitutor();
final int level1 = getLevel(applicabilityLevel, languageLevel, method1, typeParameters1, types2, types1, siteSubstitutor2, siteSubstitutor1);
final int level2 = getLevel(applicabilityLevel, languageLevel, method2, typeParameters2, types1, types2, siteSubstitutor1, siteSubstitutor2);
if (level1 > level2) return Specifics.SECOND;
if (level2 > level1) return Specifics.FIRST;
final boolean raw1 = PsiUtil.isRawSubstitutor(method1, classSubstitutor1);
final boolean raw2 = PsiUtil.isRawSubstitutor(method2, classSubstitutor2);
if (raw1 ^ raw2) {
return raw1 ? Specifics.SECOND : Specifics.FIRST;
if (level1 > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) {
final boolean abstract1 = method1.hasModifierProperty(PsiModifier.ABSTRACT);
final boolean abstract2 = method2.hasModifierProperty(PsiModifier.ABSTRACT);
if (abstract1 && !abstract2) {
return Specifics.SECOND;
}
if (abstract2 && !abstract1) {
return Specifics.FIRST;
}
}
}
else if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS) {
@@ -546,6 +551,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
}
final boolean raw1 = PsiUtil.isRawSubstitutor(method1, classSubstitutor1);
final boolean raw2 = PsiUtil.isRawSubstitutor(method2, classSubstitutor2);
if (raw1 ^ raw2) {
return raw1 ? Specifics.SECOND : Specifics.FIRST;
}
return Specifics.NEITHER;
}
@@ -553,9 +564,17 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
LanguageLevel languageLevel,
PsiMethod method2,
PsiTypeParameter[] typeParameters2,
PsiType[] types1, PsiType[] types2, PsiResolveHelper resolveHelper) {
final PsiSubstitutor methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, types2, types1, resolveHelper, languageLevel);
final int level = Math.min(applicabilityLevel, PsiUtil.getApplicabilityLevel(method2, methodSubstitutor2, types1, languageLevel, false));
PsiType[] types1,
PsiType[] types2,
PsiSubstitutor siteSubstitutor1,
PsiSubstitutor siteSubstitutor2) {
final int argsLength = types1.length;
final PsiType[] nTypes1 = new PsiType[argsLength];
for (int i = 0; i < argsLength; i++) {
nTypes1[i] = siteSubstitutor1.substitute(types1[i]);
}
final PsiSubstitutor methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, method2, siteSubstitutor2, types2, nTypes1, languageLevel);
final int level = Math.min(applicabilityLevel, PsiUtil.getApplicabilityLevel(method2, methodSubstitutor2, nTypes1, languageLevel, false));
if (level > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) {
for (PsiTypeParameter typeParameter : typeParameters2) {
final PsiType substituted = methodSubstitutor2.substitute(typeParameter);
@@ -566,7 +585,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
}
if (level == MethodCandidateInfo.ApplicabilityLevel.VARARGS) {
if (!TypeConversionUtil.isAssignable(methodSubstitutor2.substitute(types2[types1.length - 1]), types1[types1.length - 1])) {
if (!TypeConversionUtil.isAssignable(methodSubstitutor2.substitute(types2[argsLength - 1]), nTypes1[argsLength - 1])) {
return MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE;
}
}
@@ -575,16 +594,18 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
private static PsiSubstitutor calculateMethodSubstitutor(final PsiTypeParameter[] typeParameters,
final PsiMethod method,
final PsiSubstitutor siteSubstitutor,
final PsiType[] types1,
final PsiType[] types2,
final PsiResolveHelper resolveHelper,
@NotNull LanguageLevel languageLevel) {
PsiSubstitutor substitutor = resolveHelper.inferTypeArguments(typeParameters, types1, types2, languageLevel);
for (PsiTypeParameter typeParameter : typeParameters) {
PsiSubstitutor substitutor = PsiResolveHelper.SERVICE.getInstance(method.getProject())
.inferTypeArguments(typeParameters, types1, types2, languageLevel);
for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(method)) {
ProgressManager.checkCanceled();
LOG.assertTrue(typeParameter != null);
if (!substitutor.getSubstitutionMap().containsKey(typeParameter)) {
substitutor = substitutor.put(typeParameter, TypeConversionUtil.typeParameterErasure(typeParameter));
substitutor = substitutor.put(typeParameter, TypeConversionUtil.erasure(siteSubstitutor.substitute(typeParameter)));
}
}
return substitutor;
@@ -0,0 +1,11 @@
package pck;
abstract class C<T> {
abstract Object foo(T x);
String foo(String x) { return null; }
}
class D extends C<String>{
{
foo("");
}
}
@@ -0,0 +1,22 @@
public class CssPropertyValueImpl extends CssTableValueBase<CssPropertyValue, Object> implements CssPropertyValue {
public CssPropertyValueImpl(final Type type) {
super(type);
}
}
public abstract class CssTableValueBase<V extends CssTableValue, T> implements CssTableValue<V, T> {
protected CssTableValueBase(final Type type) {
}
protected CssTableValueBase(final T value) {
}
}
enum Type {}
interface CssTableValue<A, B> {
}
interface CssPropertyValue extends CssTableValue<CssPropertyValue, Object> {
}
@@ -215,6 +215,10 @@ public class AdvHighlightingJdk7Test extends DaemonAnalyzerTestCase {
doTestAmbiguous();
}
public void testAmbiguousIDEA57569() throws Exception {
doTestAmbiguous();
}
public void testAmbiguousMethodsFromSameClassAccess() throws Exception {
doTestAmbiguous();
}
@@ -312,6 +312,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testIDEA67865() { doTest5(false); }
public void testBoxingSpecific() { doTest5(false); }
public void testIDEA67843() { doTest5(false); }
public void testAmbiguousTypeParamVsConcrete() { doTest5(false); }
public void testJavaUtilCollections_NoVerify() throws Exception {
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));