mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
new inference: reject array upper bounds which contradict with another class type bound (IDEA-144159)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
}
|
||||
@@ -291,6 +291,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testIntersectionWithArray() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user