new inference: reject array upper bounds which contradict with another class type bound (IDEA-144159)

This commit is contained in:
Anna Kozlova
2015-08-20 18:04:54 +02:00
parent 0d409b8184
commit c0de8d22c6
4 changed files with 67 additions and 24 deletions

View File

@@ -15,10 +15,8 @@
*/
package com.intellij.psi.util;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.HashSet;
import java.util.Set;
@@ -28,6 +26,13 @@ import java.util.Set;
* Date: Aug 12, 2010
*/
public class TypesDistinctProver {
public static final Set<String> ARRAY_SUPER_CLASSES = new HashSet<String>();
static {
ARRAY_SUPER_CLASSES.add(CommonClassNames.JAVA_IO_SERIALIZABLE);
ARRAY_SUPER_CLASSES.add(CommonClassNames.JAVA_LANG_CLONEABLE);
ARRAY_SUPER_CLASSES.add(CommonClassNames.JAVA_LANG_OBJECT);
}
private TypesDistinctProver() {
}
@@ -53,7 +58,7 @@ public class TypesDistinctProver {
if (((PsiWildcardType)type1).isExtends()) {
final PsiType extendsBound = ((PsiWildcardType)type1).getExtendsBound();
if (extendsBound instanceof PsiArrayType &&
proveArrayTypeDistinct(((PsiWildcardType)type1).getManager().getProject(), (PsiArrayType)extendsBound, type2)) return true;
proveArrayTypeDistinct((PsiArrayType)extendsBound, type2)) return true;
final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound);
if (boundClass1 == null) return false;
@@ -67,7 +72,7 @@ public class TypesDistinctProver {
if (((PsiWildcardType)type1).isSuper()) {
final PsiType superBound = ((PsiWildcardType)type1).getSuperBound();
if (superBound instanceof PsiArrayType &&
proveArrayTypeDistinct(((PsiWildcardType)type1).getManager().getProject(), (PsiArrayType)superBound, type2)) return true;
proveArrayTypeDistinct((PsiArrayType)superBound, type2)) return true;
final PsiClass boundClass1 = PsiUtil.resolveClassInType(superBound);
if (boundClass1 == null) return false;
@@ -88,7 +93,7 @@ public class TypesDistinctProver {
}
if (type2 instanceof PsiArrayType) {
return proveArrayTypeDistinct(((PsiWildcardType)type1).getManager().getProject(), (PsiArrayType)type2, type1);
return proveArrayTypeDistinct((PsiArrayType)type2, type1);
}
} else {
@@ -160,8 +165,8 @@ public class TypesDistinctProver {
if (type1.isExtends() && type2.isExtends()) {
final PsiType extendsBound1 = type1.getExtendsBound();
final PsiType extendsBound2 = type2.getExtendsBound();
if (extendsBound1 instanceof PsiArrayType && proveArrayTypeDistinct(type1.getManager().getProject(), (PsiArrayType)extendsBound1, extendsBound2) ||
extendsBound2 instanceof PsiArrayType && proveArrayTypeDistinct(type1.getManager().getProject(), (PsiArrayType)extendsBound2, extendsBound1)) return true;
if (extendsBound1 instanceof PsiArrayType && proveArrayTypeDistinct((PsiArrayType)extendsBound1, extendsBound2) ||
extendsBound2 instanceof PsiArrayType && proveArrayTypeDistinct((PsiArrayType)extendsBound2, extendsBound1)) return true;
final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound1);
final PsiClass boundClass2 = PsiUtil.resolveClassInType(extendsBound2);
@@ -178,8 +183,8 @@ public class TypesDistinctProver {
if (type1.isExtends() && type2.isSuper()) {
final PsiType extendsBound = type1.getExtendsBound();
final PsiType superBound = type2.getSuperBound();
if (extendsBound instanceof PsiArrayType && proveArrayTypeDistinct(type1.getManager().getProject(), (PsiArrayType)extendsBound, superBound) ||
superBound instanceof PsiArrayType && proveArrayTypeDistinct(type1.getManager().getProject(), (PsiArrayType)superBound, extendsBound)) return true;
if (extendsBound instanceof PsiArrayType && proveArrayTypeDistinct((PsiArrayType)extendsBound, superBound) ||
superBound instanceof PsiArrayType && proveArrayTypeDistinct((PsiArrayType)superBound, extendsBound)) return true;
final PsiClass extendsBoundClass = PsiUtil.resolveClassInType(extendsBound);
final PsiClass superBoundClass = PsiUtil.resolveClassInType(superBound);
@@ -231,16 +236,7 @@ public class TypesDistinctProver {
return provablyDistinct(PsiWildcardType.createExtends(typeParameter.getManager(), types[0]), type);
}
public static boolean proveArrayTypeDistinct(Project project,
PsiArrayType type,
PsiType bound) {
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final GlobalSearchScope searchScope = GlobalSearchScope.allScope(project);
final Set<PsiClass> possibleClasses = new HashSet<PsiClass>();
possibleClasses.add(facade.findClass(CommonClassNames.JAVA_IO_SERIALIZABLE, searchScope));
possibleClasses.add(facade.findClass(CommonClassNames.JAVA_LANG_CLONEABLE, searchScope));
possibleClasses.add(facade.findClass(CommonClassNames.JAVA_LANG_OBJECT, searchScope));
public static boolean proveArrayTypeDistinct(PsiArrayType type, PsiType bound) {
if (type.getArrayDimensions() == bound.getArrayDimensions()) {
final PsiType componentType = type.getComponentType();
final PsiType boundComponentType = ((PsiArrayType)bound).getComponentType();
@@ -252,13 +248,13 @@ public class TypesDistinctProver {
}
}
else if (bound.getArrayDimensions() + 1 == type.getArrayDimensions() && bound.getDeepComponentType() instanceof PsiClassType) {
return !possibleClasses.contains(((PsiClassType)bound.getDeepComponentType()).resolve());
return !isSuperClassOfArrayType(((PsiClassType)bound.getDeepComponentType()).resolve());
}
else if (bound.getArrayDimensions() == type.getArrayDimensions() + 1 && type.getDeepComponentType() instanceof PsiClassType) {
return !possibleClasses.contains(((PsiClassType)type.getDeepComponentType()).resolve());
return !isSuperClassOfArrayType(((PsiClassType)type.getDeepComponentType()).resolve());
}
else if (bound instanceof PsiClassType) {
return !possibleClasses.contains(((PsiClassType)bound).resolve());
return !isSuperClassOfArrayType(((PsiClassType)bound).resolve());
}
else if (bound instanceof PsiWildcardType) {
final PsiType boundBound = ((PsiWildcardType)bound).getBound();
@@ -270,10 +266,18 @@ public class TypesDistinctProver {
if (psiClass instanceof PsiTypeParameter) {
return try2ProveTypeParameterDistinct(type, psiClass);
}
return !(((PsiWildcardType)bound).isExtends() && possibleClasses.contains(psiClass));
return !(((PsiWildcardType)bound).isExtends() && isSuperClassOfArrayType(psiClass));
}
return false;
}
return true;
}
private static boolean isSuperClassOfArrayType(PsiClass psiClass) {
if (psiClass != null) {
final String qualifiedName = psiClass.getQualifiedName();
return qualifiedName != null && ARRAY_SUPER_CLASSES.contains(qualifiedName);
}
return false;
}
}

View File

@@ -48,6 +48,12 @@ public class InferenceSession {
private static final Function<Pair<PsiType, PsiType>, PsiType> UPPER_BOUND_FUNCTION = new Function<Pair<PsiType, PsiType>, PsiType>() {
@Override
public PsiType fun(Pair<PsiType, PsiType> pair) {
if (pair.first instanceof PsiArrayType && TypesDistinctProver.proveArrayTypeDistinct((PsiArrayType)pair.first, pair.second)) {
return null;
}
if (pair.second instanceof PsiArrayType && TypesDistinctProver.proveArrayTypeDistinct((PsiArrayType)pair.second, pair.first)) {
return null;
}
return GenericsUtil.getGreatestLowerBound(pair.first, pair.second);
}
};
@@ -94,7 +100,7 @@ public class InferenceSession {
LOG.assertTrue(leftTypes.length == rightTypes.length);
for (int i = 0; i < leftTypes.length; i++) {
final PsiType rightType = mySiteSubstitutor.substitute(rightTypes[i]);
if (rightType != null) {
if (rightType != null && leftTypes[i] != null) {
addConstraint(new TypeCompatibilityConstraint(substituteWithInferenceVariables(leftTypes[i]), substituteWithInferenceVariables(rightType)));
}
}

View File

@@ -0,0 +1,29 @@
import java.io.Serializable;
import java.util.Collection;
class Issue {
public static void main(String[] args) {
consume(get());
consume<error descr="Cannot resolve method 'consume(java.io.Serializable)'">(getSerizalizable())</error>;
consume<error descr="Cannot resolve method 'consume(java.lang.Object)'">(getObject())</error>;
}
public static <T extends Issue> T get() {
return null;
}
public static <T extends Serializable> T getSerizalizable() {
return null;
}
public static <T> T getObject() {
return null;
}
public static void consume(Issue... v) {}
public static void consume(Collection v) {}
}

View File

@@ -291,6 +291,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
doTest();
}
public void testIntersectionWithArray() throws Exception {
doTest();
}
private void doTest() throws Exception {
doTest(false);
}