moreSpecific simplification, include complete check for inferred types in MethodCandidateInfo.isApplicable

This commit is contained in:
Anna Kozlova
2013-08-15 13:49:47 +04:00
parent 3a958ef8da
commit 47220fd160
9 changed files with 201 additions and 230 deletions
@@ -249,16 +249,49 @@ public class GenericsUtil {
PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
for (PsiClassType type : extendsTypes) {
PsiType extendsType = substitutor.substitute(type);
if (extendsType.isAssignableFrom(substituted)) {
continue nextTypeParam;
if (substituted instanceof PsiWildcardType) {
if (((PsiWildcardType)substituted).isSuper()) {
continue;
}
final PsiType extendsBound = ((PsiWildcardType)substituted).getExtendsBound();
if (TypeConversionUtil.erasure(extendsType).equals(TypeConversionUtil.erasure(extendsBound))) {
if (extendsBound instanceof PsiClassType) {
if (acceptExtendsBound((PsiClassType)extendsBound, 0)) continue;
} else if (extendsBound instanceof PsiIntersectionType) {
for (PsiType psiType : ((PsiIntersectionType)extendsBound).getConjuncts()) {
if (psiType instanceof PsiClassType) {
if (acceptExtendsBound((PsiClassType)psiType, 0)) continue nextTypeParam;
}
}
}
}
}
if (!TypeConversionUtil.isAssignable(extendsType, substituted)) {
return false;
}
}
if (extendsTypes.length > 0) return false;
}
return true;
}
private static boolean acceptExtendsBound(PsiClassType extendsBound, int depth) {
PsiType[] parameters = extendsBound.getParameters();
if (parameters.length == 1) {
PsiType argType = parameters[0];
if (argType instanceof PsiCapturedWildcardType && depth == 0) {
argType = ((PsiCapturedWildcardType)argType).getWildcard();
}
if (argType instanceof PsiWildcardType) {
if (!((PsiWildcardType)argType).isBounded()) return true;
final PsiType bound = ((PsiWildcardType)argType).getExtendsBound();
if (bound instanceof PsiClassType && TypeConversionUtil.erasure(bound).equals(TypeConversionUtil.erasure(extendsBound))) {
return acceptExtendsBound((PsiClassType)bound, depth + 1);
}
}
}
return false;
}
public static boolean isFromExternalTypeLanguage(@NotNull PsiType type) {
String internalCanonicalText = type.getInternalCanonicalText();
return internalCanonicalText != null && internalCanonicalText.equals(type.getCanonicalText());
@@ -466,8 +466,19 @@ public final class PsiUtil extends PsiUtilCore {
}
@MethodCandidateInfo.ApplicabilityLevelConstant
public static int getApplicabilityLevel(@NotNull final PsiMethod method, @NotNull final PsiSubstitutor substitutorForMethod, @NotNull final PsiType[] args,
@NotNull final LanguageLevel languageLevel) {
public static int getApplicabilityLevel(@NotNull final PsiMethod method,
@NotNull final PsiSubstitutor substitutorForMethod,
@NotNull final PsiType[] args,
@NotNull final LanguageLevel languageLevel) {
return getApplicabilityLevel(method, substitutorForMethod, args, languageLevel, true);
}
@MethodCandidateInfo.ApplicabilityLevelConstant
public static int getApplicabilityLevel(@NotNull final PsiMethod method,
@NotNull final PsiSubstitutor substitutorForMethod,
@NotNull final PsiType[] args,
@NotNull final LanguageLevel languageLevel,
boolean allowUncheckedConversion) {
final PsiParameter[] parms = method.getParameterList().getParameters();
if (args.length < parms.length - 1) return ApplicabilityLevel.NOT_APPLICABLE;
@@ -479,7 +490,7 @@ public final class PsiUtil extends PsiUtilCore {
PsiType parmType = getParameterType(parms[parms.length - 1], languageLevel, substitutorForMethod);
PsiType argType = args[args.length - 1];
if (argType == null) return ApplicabilityLevel.NOT_APPLICABLE;
if (TypeConversionUtil.isAssignable(parmType, argType)) return ApplicabilityLevel.FIXED_ARITY;
if (TypeConversionUtil.isAssignable(parmType, argType, allowUncheckedConversion)) return ApplicabilityLevel.FIXED_ARITY;
if (isRaw) {
final PsiType erasedParamType = TypeConversionUtil.erasure(parmType);
@@ -526,6 +526,44 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
substitutor = substitutor.put(typeParameter, substitution);
}
}
for (int i = 0; i < typeParameters.length; i++) {
PsiTypeParameter typeParameter = typeParameters[i];
if (!substitutor.getSubstitutionMap().containsKey(typeParameter)) {
PsiType substitutionFromBounds = PsiType.NULL;
OtherParameters:
for (int j = 0; j < typeParameters.length; j++) {
if (i != j) {
PsiTypeParameter other = typeParameters[j];
final PsiType otherSubstitution = substitutor.substitute(other);
if (otherSubstitution == null) continue;
final PsiClassType[] bounds = other.getExtendsListTypes();
for (PsiClassType bound : bounds) {
final PsiType substitutedBound = substitutor.substitute(bound);
final Pair<PsiType, ConstraintType> currentConstraint =
getSubstitutionForTypeParameterConstraint(typeParameter, substitutedBound, otherSubstitution, true, languageLevel);
if (currentConstraint == null) continue;
final PsiType currentSubstitution = currentConstraint.getFirst();
final ConstraintType currentConstraintType = currentConstraint.getSecond();
if (currentConstraintType == ConstraintType.EQUALS) {
substitutionFromBounds = currentSubstitution;
break OtherParameters;
}
else if (currentConstraintType == ConstraintType.SUPERTYPE) {
if (PsiType.NULL.equals(substitutionFromBounds)) {
substitutionFromBounds = currentSubstitution;
}
else {
substitutionFromBounds = GenericsUtil.getLeastUpperBound(substitutionFromBounds, currentSubstitution, myManager);
}
}
}
}
}
if (substitutionFromBounds != PsiType.NULL) {
substitutor = substitutor.put(typeParameter, substitutionFromBounds);
}
}
}
return substitutor;
}
@@ -1163,15 +1201,18 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
}
}
PsiClassType[] superTypes = typeParameter.getSuperTypes();
PsiType[] superTypes = typeParameter.getSuperTypes();
if (superTypes.length == 0) return null;
PsiType superType = substitutor.substitute(superTypes[0]);
if (superType instanceof PsiClassType && ((PsiClassType)superType).isRaw()) {
superType = TypeConversionUtil.erasure(superType);
for (int i = 0; i < superTypes.length; i++) {
PsiType superType = substitutor.substitute(superTypes[i]);
if (superType instanceof PsiClassType && ((PsiClassType)superType).isRaw()) {
superType = TypeConversionUtil.erasure(superType);
}
if (superType == null) superType = PsiType.getJavaLangObject(myManager, scope);
if (superType == null) return null;
superTypes[i] = superType;
}
if (superType == null) superType = PsiType.getJavaLangObject(myManager, scope);
if (superType == null) return null;
return policy.getInferredTypeWithNoConstraint(myManager, superType);
return policy.getInferredTypeWithNoConstraint(myManager, PsiIntersectionType.createIntersection(superTypes));
}
return null;
}
@@ -33,9 +33,11 @@ import gnu.trove.THashMap;
import gnu.trove.THashSet;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by IntelliJ IDEA.
@@ -71,7 +73,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
boolean atLeastOneMatch = checkParametersNumber(conflicts, myActualParameterTypes.length, true);
if (conflicts.size() == 1) return conflicts.get(0);
checkSameSignatures(conflicts, myLanguageLevel);
checkSameSignatures(conflicts);
if (conflicts.size() == 1) return conflicts.get(0);
checkAccessStaticLevels(conflicts, true);
@@ -193,7 +195,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
}
private void checkSameSignatures(@NotNull List<CandidateInfo> conflicts, @NotNull LanguageLevel languageLevel) {
private void checkSameSignatures(@NotNull List<CandidateInfo> conflicts) {
// candidates should go in order of class hierarchy traversal
// in order for this to work
Map<MethodSignature, CandidateInfo> signatures = new THashMap<MethodSignature, CandidateInfo>(conflicts.size());
@@ -420,42 +422,6 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
NEITHER
}
private static Specifics checkSubtyping(PsiType type1, PsiType type2, PsiMethod method1, PsiMethod method2) {
return checkSubtyping(type1, type2, method1, method2, true);
}
@Nullable
private static Specifics checkSubtyping(PsiType type1,
PsiType type2,
PsiMethod method1,
PsiMethod method2,
boolean boxingHappening) {
boolean noBoxing = boxingHappening || type1 instanceof PsiPrimitiveType == type2 instanceof PsiPrimitiveType;
boolean allowUncheckedConversion =
!method1.hasModifierProperty(PsiModifier.STATIC) && !method2.hasModifierProperty(PsiModifier.STATIC);
if (!allowUncheckedConversion) {
final PsiClass containingClass1 = method1.getContainingClass();
final PsiClass containingClass2 = method2.getContainingClass();
if (containingClass1 != null && containingClass2 != null) {
allowUncheckedConversion = !containingClass1.isInheritor(containingClass2, true) &&
!containingClass2.isInheritor(containingClass1, true);
}
}
final boolean assignable2From1 = noBoxing && TypeConversionUtil.isAssignable(type2, type1, allowUncheckedConversion);
final boolean assignable1From2 = noBoxing && TypeConversionUtil.isAssignable(type1, type2, allowUncheckedConversion);
if (assignable1From2 || assignable2From1) {
if (assignable1From2 && assignable2From1) {
return null;
}
return assignable1From2 ? Specifics.SECOND : Specifics.FIRST;
}
return allowUncheckedConversion ? Specifics.NEITHER : null;
}
private static boolean isBoxingHappened(PsiType argType, PsiType parameterType, @NotNull LanguageLevel languageLevel) {
if (argType == null) return parameterType instanceof PsiPrimitiveType;
if (parameterType instanceof PsiClassType) {
@@ -491,6 +457,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
PsiType type2 = params2.length > 0 ? params2[Math.min(i, params2.length - 1)].getType() : null;
if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS) {
if (type1 instanceof PsiEllipsisType && type2 instanceof PsiEllipsisType &&
params1.length == params2.length &&
(!JavaVersionService.getInstance().isAtLeast(class1, JavaSdkVersion.JDK_1_7) || ((PsiArrayType)type1).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || ((PsiArrayType)type2).getComponentType().equalsToText(CommonClassNames.JAVA_LANG_OBJECT))) {
type1 = ((PsiEllipsisType)type1).toArrayType();
type2 = ((PsiEllipsisType)type2).toArrayType();
@@ -505,6 +472,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
types2[i] = type2;
}
boolean sameBoxing = true;
int[] boxingHappened = new int[2];
for (int i = 0; i < types1.length; i++) {
ProgressManager.checkCanceled();
@@ -512,57 +480,51 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
PsiType type2 = classSubstitutor2.substitute(types2[i]);
PsiType argType = i < myActualParameterTypes.length ? myActualParameterTypes[i] : null;
boxingHappened[0] += isBoxingHappened(argType, type1, languageLevel) ? 1 : 0;
boxingHappened[1] += isBoxingHappened(argType, type2, languageLevel) ? 1 : 0;
boolean boxingInFirst = false;
if (isBoxingHappened(argType, type1, languageLevel)) {
boxingHappened[0] += 1;
boxingInFirst = true;
}
boolean boxingInSecond = false;
if (isBoxingHappened(argType, type2, languageLevel)) {
boxingHappened[1] += 1;
boxingInSecond = true;
}
sameBoxing &= boxingInFirst == boxingInSecond;
}
if (boxingHappened[0] == 0 && boxingHappened[1] > 0) return Specifics.FIRST;
if (boxingHappened[0] > 0 && boxingHappened[1] == 0) return Specifics.SECOND;
Specifics isMoreSpecific = null;
for (int i = 0; i < types1.length; i++) {
ProgressManager.checkCanceled();
Specifics specifics = checkSubstitutorSpecific(method1, method2, classSubstitutor1, classSubstitutor2, types1[i], types2[i]);
if (specifics == null) {
PsiSubstitutor methodSubstitutor1 = PsiSubstitutor.EMPTY;
PsiSubstitutor methodSubstitutor2 = PsiSubstitutor.EMPTY;
if (typeParameters1.length == 0 || typeParameters2.length == 0) {
if (typeParameters1.length > 0) {
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myArgumentsList.getProject()).getResolveHelper();
methodSubstitutor1 = calculateMethodSubstitutor(typeParameters1, types1, types2, resolveHelper, languageLevel);
}
else if (typeParameters2.length > 0) {
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myArgumentsList.getProject()).getResolveHelper();
methodSubstitutor2 = calculateMethodSubstitutor(typeParameters2, types2, types1, resolveHelper, languageLevel);
}
}
else {
PsiElementFactory factory = JavaPsiFacade.getInstance(myArgumentsList.getProject()).getElementFactory();
methodSubstitutor1 = factory.createRawSubstitutor(PsiSubstitutor.EMPTY, typeParameters1);
methodSubstitutor2 = factory.createRawSubstitutor(PsiSubstitutor.EMPTY, typeParameters2);
}
PsiType type1 = classSubstitutor1.substitute(methodSubstitutor1.substitute(types1[i]));
PsiType type2 = classSubstitutor2.substitute(methodSubstitutor2.substitute(types2[i]));
specifics = type1 == null || type2 == null ? null : checkSubtyping(type1, type2, method1, method2, boxingHappened[0] == 0 || boxingHappened[1] == 0);
if (specifics == null) {
continue;
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);
if (level1 > level2) return Specifics.SECOND;
if (level2 > level1) return Specifics.FIRST;
if (level1 == MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) {
final boolean raw1 = PsiUtil.isRawSubstitutor(method1, classSubstitutor1);
final boolean raw2 = PsiUtil.isRawSubstitutor(method2, classSubstitutor2);
if (raw1 ^ raw2) {
return raw1 ? Specifics.SECOND : Specifics.FIRST;
}
}
switch (specifics) {
case FIRST:
if (isMoreSpecific == Specifics.SECOND) return Specifics.NEITHER;
isMoreSpecific = specifics;
break;
case SECOND:
if (isMoreSpecific == Specifics.FIRST) return Specifics.NEITHER;
isMoreSpecific = specifics;
break;
case NEITHER:
return Specifics.NEITHER;
}
else if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.VARARGS) {
final PsiType lastParamType1 = classSubstitutor1.substitute(types1[types1.length - 1]);
final PsiType lastParamType2 = classSubstitutor2.substitute(types2[types1.length - 1]);
final boolean assignable1 = TypeConversionUtil.isAssignable(lastParamType2, lastParamType1);
final boolean assignable2 = TypeConversionUtil.isAssignable(lastParamType1, lastParamType2);
if (assignable1 && !assignable2) {
return Specifics.FIRST;
}
if (assignable2 && !assignable1) {
return Specifics.SECOND;
}
}
if (isMoreSpecific == null && class1 != class2) {
Specifics isMoreSpecific = null;
if (class1 != class2) {
if (class2.isInheritor(class1, true) || class1.isInterface() && !class2.isInterface()) {
if (MethodSignatureUtil.isSubsignature(method1.getSignature(info1.getSubstitutor()), method2.getSignature(info2.getSubstitutor()))) {
isMoreSpecific = Specifics.SECOND;
@@ -581,149 +543,35 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
}
if (isMoreSpecific == null) {
if (!JavaVersionService.getInstance().isAtLeast(myArgumentsList, JavaSdkVersion.JDK_1_7) ||
!MethodSignatureUtil.areParametersErasureEqual(method1, method2) ||
InheritanceUtil.isInheritorOrSelf(class1, class2, true) ||
InheritanceUtil.isInheritorOrSelf(class2, class1, true)) {
if (typeParameters1.length < typeParameters2.length) return Specifics.FIRST;
if (typeParameters1.length > typeParameters2.length) return Specifics.SECOND;
}
return Specifics.NEITHER;
}
return isMoreSpecific;
}
@Nullable
private static Specifics checkSubstitutorSpecific(PsiMethod method1,
PsiMethod method2,
PsiSubstitutor classSubstitutor1,
PsiSubstitutor classSubstitutor2,
PsiType type1,
PsiType type2) {
final PsiClass aClass1 = PsiUtil.resolveClassInType(type1);
final PsiClass aClass2 = PsiUtil.resolveClassInType(type2);
if (aClass1 instanceof PsiTypeParameter && aClass2 instanceof PsiTypeParameter) {
return checkTypeParams(method1, method2, classSubstitutor1, classSubstitutor2, type1, type2, (PsiTypeParameter)aClass1, (PsiTypeParameter)aClass2);
}
if (aClass1 instanceof PsiTypeParameter && aClass2 != null) {
return chooseHigherDimension(type1, type2);
}
else if (aClass2 instanceof PsiTypeParameter && aClass1 != null) {
return chooseHigherDimension(type2, type1);
}
final Map<PsiTypeParameter, PsiType> map1 = classSubstitutor1.getSubstitutionMap();
final Map<PsiTypeParameter, PsiType> map2 = classSubstitutor2.getSubstitutionMap();
if (map1.size() == 1 && map2.size() == 1) {
boolean leftAssignable = InheritanceUtil.isInheritorOrSelf(aClass2, aClass1, true);
boolean rightAssignable = InheritanceUtil.isInheritorOrSelf(aClass1, aClass2, true);
final PsiType t1 = map1.values().iterator().next();
final PsiType t2 = map2.values().iterator().next();
boolean raw1 = t1 instanceof PsiClassType && ((PsiClassType)t1).hasParameters();
boolean raw2 = t2 instanceof PsiClassType && ((PsiClassType)t2).hasParameters();
if (!raw1 && raw2) return leftAssignable ? Specifics.FIRST : Specifics.NEITHER;
if (raw1 && !raw2) return rightAssignable ? Specifics.SECOND : Specifics.NEITHER;
final PsiTypeParameter p1 = map1.keySet().iterator().next();
final PsiTypeParameter p2 = map2.keySet().iterator().next();
Specifics specifics = checkTypeParams(method1, method2, classSubstitutor1, classSubstitutor2, type1, type2, p1, p2);
if (specifics == null) {
specifics = chooseHigherDimension(t1, t2);
}
if (specifics != null) {
if (specifics == Specifics.FIRST) {
if (leftAssignable && !rightAssignable) return Specifics.NEITHER;
}
else if (specifics == Specifics.SECOND) {
if (rightAssignable && !leftAssignable) return Specifics.NEITHER;
}
}
return specifics;
}
return null;
}
private static Specifics chooseHigherDimension(PsiType type1, PsiType type2) {
if (type1 != null && type1.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return null;
if (type2 != null && type2.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return null;
int d1 = type1 != null ? type1.getArrayDimensions() : 0;
int d2 = type2 != null ? type2.getArrayDimensions() : 0;
if (d1 > d2) {
return Specifics.SECOND;
}
else if (d2 > d1) {
return Specifics.FIRST;
}
return null;
}
@Nullable
private static Specifics checkTypeParams(PsiMethod method1,
PsiMethod method2,
PsiSubstitutor classSubstitutor1,
PsiSubstitutor classSubstitutor2,
PsiType type1,
PsiType type2,
PsiTypeParameter p1,
PsiTypeParameter p2) {
final Map<PsiClass, PsiClassType> resolved1 = new HashMap<PsiClass, PsiClassType>();
for (PsiClassType referenceElement : p1.getExtendsList().getReferencedTypes()) {
ProgressManager.checkCanceled();
final PsiClass aClass = referenceElement.resolve();
if (aClass != null) {
resolved1.put(aClass, referenceElement);
}
}
final Map<PsiClass, PsiClassType> resolved2 = new HashMap<PsiClass, PsiClassType>();
for (PsiClassType referenceElement : p2.getExtendsList().getReferencedTypes()) {
ProgressManager.checkCanceled();
final PsiClass aClass = referenceElement.resolve();
if (aClass != null) {
resolved2.put(aClass, referenceElement);
}
}
Specifics specifics = null;
if (resolved1.size() > resolved2.size()){
specifics = checkExtendsList(resolved1, resolved2, Specifics.FIRST);
} else if (resolved2.size() > resolved1.size()) {
specifics = checkExtendsList(resolved2, resolved1, Specifics.SECOND);
}
if (specifics != null) return specifics;
specifics = checkSubtyping(TypeConversionUtil.erasure(PsiSubstitutor.EMPTY.substitute(p1)),
TypeConversionUtil.erasure(PsiSubstitutor.EMPTY.substitute(p2)), method1, method2);
if (specifics != null) {
return specifics;
} else {
final PsiType ctype1 = classSubstitutor1.substitute(type1);
final PsiType ctype2 = classSubstitutor2.substitute(type2);
return checkSubtyping(ctype1, ctype2, method1, method2);
}
}
private static Specifics checkExtendsList(Map<PsiClass, PsiClassType> resolved1,
Map<PsiClass, PsiClassType> resolved2,
Specifics preferred) {
if (resolved1.keySet().containsAll(resolved2.keySet())){
resolved1.keySet().removeAll(resolved2.keySet());
for (Iterator<PsiClass> iterator = resolved1.keySet().iterator(); iterator.hasNext(); ) {
PsiClass psiClass = iterator.next();
final PsiClassType baseType = resolved1.get(psiClass);
for (PsiClassType childType : resolved2.values()) {
ProgressManager.checkCanceled();
if (TypeConversionUtil.isAssignable(baseType, childType, false)) {
iterator.remove();
break;
private int getLevel(int applicabilityLevel,
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));
if (level > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) {
for (PsiTypeParameter typeParameter : typeParameters2) {
final PsiType substituted = methodSubstitutor2.substitute(typeParameter);
for (PsiClassType extendsType : typeParameter.getExtendsListTypes()) {
if (substituted == null || !TypeConversionUtil.isAssignable(methodSubstitutor2.substitute(extendsType), substituted, false)) {
return MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE;
}
}
}
if (!resolved1.isEmpty()) return preferred;
return Specifics.NEITHER;
if (level == MethodCandidateInfo.ApplicabilityLevel.VARARGS) {
if (!TypeConversionUtil.isAssignable(methodSubstitutor2.substitute(types2[types1.length - 1]), types1[types1.length - 1])) {
return MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE;
}
}
}
return null;
return level;
}
private static PsiSubstitutor calculateMethodSubstitutor(final PsiTypeParameter[] typeParameters,
@@ -12,6 +12,6 @@ class B
{
public static void main(String[] args) {
A a = null;
a.foo<error descr="Ambiguous method call: both 'A.foo(Collection<?>)' and 'A.foo(List<?>)' match">(null)</error>;
a.foo<error descr="Ambiguous method call: both 'A.foo(List<?>)' and 'A.foo(List<?>)' match">(null)</error>;
}
}
@@ -0,0 +1,26 @@
package pck;
import java.util.List;
import static pck.C.foo;
import static pck.C.foo1;
import static pck.D.foo;
import static pck.D.foo1;
class C {
static <T> void foo(List<T> x) { }
static <T extends List> void foo1(List<T> x) { }
}
class D {
static <T extends List<S>, S> String foo(List<T> x) { return null; }
static <T extends List<?>, S> String foo1(List<T> x) { return null; }
}
public class Main {
public static void main(String[] args){
List<List<String>> x = null;
foo(x).toCharArray();
foo1(x).toCharArray();
}
}
@@ -0,0 +1,7 @@
import java.util.*;
abstract class A {
void computeCostIfNeeded(Map<Object, Integer> costMap) {
Math.min(costMap.get(null), 1);
}
}
@@ -199,6 +199,10 @@ public class AdvHighlightingJdk7Test extends DaemonAnalyzerTestCase {
doTestAmbiguous();
}
public void testAmbiguousIDEA67864() throws Exception {
doTestAmbiguous();
}
public void testAmbiguousMethodsFromSameClassAccess() throws Exception {
doTestAmbiguous();
}
@@ -310,6 +310,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testIDEA57439() { doTest5(false); }
public void testIDEA57312() { doTest5(false); }
public void testIDEA67865() { doTest5(false); }
public void testBoxingSpecific() { doTest5(false); }
public void testJavaUtilCollections_NoVerify() throws Exception {
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));