JLS 5.5: cast conversion implemented for generics types (inspired by IDEA-57342 )

This commit is contained in:
anna
2010-08-12 12:39:50 +04:00
parent 33b0dfc777
commit 8039cffacc
3 changed files with 571 additions and 6 deletions
@@ -0,0 +1,466 @@
public class Test {
interface A {}
interface B {}
//? extends A, ? extends B -----------------------------------------
void testEE1() {
class A {}
class B {}
W<? extends A> xx = null;
W<? extends B> y = <error>(W<? extends B>) xx</error>;
}
void testEE2() {
class A {}
class B extends A {}
W<? extends A> xx = null;
W<? extends B> y = (W<? extends B>) xx;
}
void testEE21() {
class A {}
class B extends A {}
W<? extends B> xx = null;
W<? extends A> y = (W<? extends A>) xx;
}
void testEE211() {
class A {}
final class B extends A {}
W<? extends A> xx = null;
W<? extends B> y = (W<? extends B>) xx;
}
void test3EE() {
W<? extends A> xx = null;
W<? extends B> y = (W<? extends B>) xx;
}
void test4EE() {
class A {}
W<? extends A> xx = null;
W<? extends B> y = (W<? extends B>) xx;
}
void test41EE() {
class A {}
W<? extends B> xx = null;
W<? extends A> y = (W<? extends A>) xx;
}
void test411EE() {
final class A {}
W<? extends B> xx = null;
W<? extends A> y = <error>(W<? extends A>) xx</error>;
}
void test412EE() {
final class A implements B {}
W<? extends B> xx = null;
W<? extends A> y = (W<? extends A>) xx;
}
void test1() {
class A {}
class B {}
W<? super A> xx = null;
W<? super B> y = (W<? super B>) xx;
}
void test2() {
final class A {}
final class B {}
W<? super A> xx = null;
W<? super B> y = (W<? super B>) xx;
}
//? super A, ? super B -------------------------
void test3SS() {
W<? super A> xx = null;
W<? super B> y = (W<? super B>) xx;
}
//? extends A, ? super B -------------------------
void test1ES() {
class A {}
class B {}
W<? extends A> x = null;
W<? super B> y = <error>(W<? super B>) x</error>;
}
void test2ES() {
class A {}
class B extends A {}
W<? extends A> x = null;
W<? super B> y = (W<? super B>) x;
}
void test3ES() {
class A {}
class B extends A {}
W<? extends B> x = null;
W<? super A> y = <error>(W<? super A>) x</error>;
}
void test4ES() {
W<? extends B> x = null;
W<? super A> y = <error>(W<? super A>) x</error>;
}
void test5ES() {
final class B implements A {}
W<? extends A> x = null;
W<? super B> y = (W<? super B>) x;
}
void test6ES() {
final class B implements A {}
W<? extends B> x = null;
W<? super A> y = <error>(W<? super A>) x</error>;
}
// ? extends A, B -----------------------
void test1EWC() {
class A {
}
class B {
}
W<? extends A> xx = null;
W<B> y = <error>(W<B>) xx</error>;
}
void test2EWC() {
class A {
}
W<? extends A> xx = null;
W<?> y = (W<?>) xx;
}
void test3EWC() {
class A {
}
class B extends A {
}
W<? extends A> xx = null;
W<B> y = (W<B>) xx;
}
// ? super A, B -----------------------
void test1SWC() {
class A {
}
class B {
}
W<? super A> xx = null;
W<B> y = <error>(W<B>) xx</error>;
}
void test2SWC() {
class A {
}
W<? super A> xx = null;
W<?> y = (W<?>) xx;
}
void test3SWC() {
class A {
}
class B extends A {
}
W<? super B> xx = null;
W<A> y = (W<A>) xx;
}
// ?, ? ------------------------------------------
void test1WWW() {
W<?> xx = null;
W<?> y = xx;
}
//? extends P<? extends A>, B --------------------
void test1EEWC() {
class A {
}
class B {
}
W<? extends P<? extends A>> xx = null;
W<? extends B> y = <error>(W<? extends B>) xx</error>;
}
void test2EEWC() {
class A {
}
class B extends P {
}
W<? extends P<? extends A>> xx = null;
W<? extends B> y = (W<? extends B>) xx;
}
void test3EEWC() {
class A {
}
class B<TB> extends P<TB> {
}
W<? extends P<? extends A>> xx = null;
W<? extends B<? super A>> y = (W<? extends B<? super A>>) xx;
}
void test4EEWC() {
class A {
}
class B<TB> extends P<TB> {
}
W<? extends P<? extends A>> xx = null;
W<? extends B<?>> y = (W<? extends B<?>>) xx;
}
void test5EEWC() {
class A {
}
class B<TB> extends P<TB> {
}
class C {}
W<? extends P<? extends A>> xx = null;
W<? extends B<? extends C>> y = (W<? extends B<? extends C>>) xx;
}
//Array Types inside wildcards
void test1AE() {
class A {}
class B {}
W<? extends A[]> xx = null;
W<? extends B[]> y = <error>(W<? extends B[]>) xx</error>;
}
void test11AE() {
class A {}
class B {}
W<? extends A[]> xx = null;
W<? extends B> y = <error>(W<? extends B>) xx</error>;
}
void test2AE() {
class A {}
class B extends A {}
W<? extends A[]> xx = null;
W<? extends B[]> y = (W<? extends B[]>) xx;
}
void test21AE() {
class A {}
class B extends A {}
W<? extends A[]> xx = null;
W<? extends B> y = <error>(W<? extends B>) xx</error>;
}
void testIntAE() {
W<? extends A[]> xx = null;
W<? extends B[]> y = (W<? extends B[]>) xx;
}
void testInt1AE() {
W<? extends A[]> xx = null;
W<? extends B[][]> y = <error>(W<? extends B[][]>) xx</error>;
}
void testASS() {
class A {}
class B {}
W<? super A[]> xx = null;
W<? super B[]> y = (W<? super B[]>) xx;
}
void test1AES() {
class A {}
class B {}
W<? extends A[]> x = null;
W<? super B[]> y = <error>(W<? super B[]>) x</error>;
}
void test2AES() {
class A {}
class B extends A {}
W<? extends A[]> x = null;
W<? super B[]> y = (W<? super B[]>) x;
}
void test3AES() {
class A {}
class B extends A {}
W<? extends B[]> x = null;
W<? super A[]> y = <error>(W<? super A[]>) x</error>;
}
void test4AES() {
W<? extends B[]> x = null;
W<? super A[]> y = <error>(W<? super A[]>) x</error>;
}
void test5AES() {
final class B implements A {}
W<? extends A[]> x = null;
W<? super B[]> y = (W<? super B[]>) x;
}
void test6AES() {
final class B implements A {}
W<? extends B[]> x = null;
W<? super A[]> y = <error>(W<? super A[]>) x</error>;
}
// type parameters extensions: D<T extends A>
void testT3() {
class A {
}
class D<T extends A > {
class B extends A {
}
void foo() {
D<? extends T> x = null;
D<? extends B> y = (D<? extends B>) x;
}
}
}
void testT4() {
class A {
}
class D<T extends A> {
class B {
}
void foo() {
D<? extends T> x = null;
D<? extends B> y = <error>(D<? extends B>) x</error>;
}
}
}
void testT5() {
class D<T> {
class B {
}
void foo() {
D<? extends T> x = null;
D<? extends B> y = (D<? extends B>) x;
}
}
}
void testT6() {
class A {
}
class D<T extends A> {
class B extends A {
}
void foo() {
D<? super T> x = null;
D<? super B> y = (D<? super B>) x;
}
}
}
void testT7() {
class A {
}
class D<T extends A> {
class B extends A {
}
void foo() {
D<? extends T> x = null;
D<? super B> y = (D<? super B>) x;
}
}
}
void testT8() {
class A {
}
class D<T extends A> {
class B extends A {
}
void foo() {
D<? super T> x = null;
D<? extends B> y = (D<? extends B>) x;
}
}
}
void testT9() {
class A {
}
class D<T> {
class B extends A {
}
void foo() {
D<? super T> x = null;
D<? extends A> y = (D<? extends B>) x;
}
}
}
}
class W<T> {}
class P<L> {}
@@ -94,6 +94,7 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testOverrideAtLanguageLevel6() throws Exception { doTest(false); }
public void testOverrideAtLanguageLevel5() throws Exception { doTest(false); }
public void testSuperMethodCallWithErasure() throws Exception { doTest(false); }
public void testWildcardCastConversion() throws Exception { doTest(false); }
public void testJavaUtilCollections() throws Exception {
PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule()));
@@ -328,17 +328,115 @@ public class TypeConversionUtil {
PsiType typeArg1 = substitutor1.substitute(typeParameter);
PsiType typeArg2 = substitutor2.substitute(typeParameter);
if (typeArg1 == null || typeArg2 == null) return true;
if (typeArg1 instanceof PsiWildcardType || typeArg2 instanceof PsiWildcardType) return true;
if (typeArg1 instanceof PsiCapturedWildcardType || typeArg2 instanceof PsiCapturedWildcardType) return true;
if (typeArg1 instanceof PsiClassType && ((PsiClassType)typeArg1).resolve() instanceof PsiTypeParameter) return true;
if (typeArg2 instanceof PsiClassType && ((PsiClassType)typeArg2).resolve() instanceof PsiTypeParameter) return true;
if (!typeArg1.equals(typeArg2)) return false;
if (provablyDistinct(typeArg1, typeArg2)) return false;
}
return true;
}
private static boolean provablyDistinct(PsiType type1, PsiType type2) {
if (type1 instanceof PsiWildcardType) {
if (type2 instanceof PsiWildcardType) {
return provablyDistinct((PsiWildcardType)type1, (PsiWildcardType)type2);
}
if (type2 instanceof PsiCapturedWildcardType) {
return provablyDistinct((PsiWildcardType)type1, ((PsiCapturedWildcardType)type2).getWildcard());
}
if (type2 instanceof PsiClassType) {
final PsiClass psiClass2 = PsiUtil.resolveClassInType(type2);
if (psiClass2 == null) return false;
if (((PsiWildcardType)type1).isExtends()) {
final PsiType extendsBound = ((PsiWildcardType)type1).getExtendsBound();
if (extendsBound.getArrayDimensions() > 0) return true;
final PsiClass boundClass1 = PsiUtil.resolveClassInType(erasure(extendsBound));
if (boundClass1 == null) return false;
if (boundClass1 instanceof PsiTypeParameter) {
return try2ProveTypeParameterDistinct(type2, boundClass1);
}
return !psiClass2.isInheritor(boundClass1, true);
}
if (((PsiWildcardType)type1).isSuper()) {
final PsiType superBound = ((PsiWildcardType)type1).getSuperBound();
if (superBound.getArrayDimensions() > 0) return true;
final PsiClass boundClass1 = PsiUtil.resolveClassInType(erasure(superBound));
if (boundClass1 == null || boundClass1 instanceof PsiTypeParameter) return false;
return !boundClass1.isInheritor(psiClass2, true);
}
final PsiType bound = ((PsiWildcardType)type1).getBound();
return bound != null && !bound.equals(psiClass2);
}
}
if (type1 instanceof PsiCapturedWildcardType) return provablyDistinct(((PsiCapturedWildcardType)type1).getWildcard(), type2);
if (type2 instanceof PsiWildcardType || type2 instanceof PsiCapturedWildcardType) return provablyDistinct(type2, type1);
if (type1 instanceof PsiClassType && ((PsiClassType)type1).resolve() instanceof PsiTypeParameter) return false;
if (type2 instanceof PsiClassType && ((PsiClassType)type2).resolve() instanceof PsiTypeParameter) return false;
return !type1.equals(type2);
}
private static boolean provablyDistinct(PsiWildcardType type1, PsiWildcardType type2) {
if (type1.isSuper() && type2.isSuper()) return false;
if (type1.isExtends() && type2.isExtends()) {
final PsiType extendsBound1 = type1.getExtendsBound();
final PsiType extendsBound2 = type2.getExtendsBound();
if (extendsBound1.getArrayDimensions() != extendsBound2.getArrayDimensions()) return true;
final PsiClass boundClass1 = PsiUtil.resolveClassInType(extendsBound1);
final PsiClass boundClass2 = PsiUtil.resolveClassInType(extendsBound2);
if (boundClass1 != null && boundClass2 != null) {
if (boundClass1.isInterface() && boundClass2.isInterface()) return false;
if (boundClass1.isInterface()) {
return !(boundClass2.hasModifierProperty(PsiModifier.FINAL) ? boundClass2.isInheritor(boundClass1, true) : true);
}
if (boundClass2.isInterface()) {
return !(boundClass1.hasModifierProperty(PsiModifier.FINAL) ? boundClass1.isInheritor(boundClass2, true) : true);
}
if (boundClass1 instanceof PsiTypeParameter) {
return try2ProveTypeParameterDistinct(type2, boundClass1);
}
if (boundClass2 instanceof PsiTypeParameter) {
return try2ProveTypeParameterDistinct(type1, boundClass2);
}
return !boundClass1.isInheritor(boundClass2, true) && !boundClass2.isInheritor(boundClass1, true);
}
return provablyDistinct(extendsBound1, extendsBound2);
}
if (type2.isExtends()) return provablyDistinct(type2, type1);
if (type1.isExtends() && type2.isSuper()) {
final PsiType extendsBound = type1.getExtendsBound();
final PsiType superBound = type2.getSuperBound();
if (extendsBound.getArrayDimensions() != superBound.getArrayDimensions()) return true;
final PsiClass extendsBoundClass = PsiUtil.resolveClassInType(extendsBound);
final PsiClass superBoundClass = PsiUtil.resolveClassInType(superBound);
if (extendsBoundClass != null && superBoundClass != null) {
if (extendsBoundClass instanceof PsiTypeParameter) {
return try2ProveTypeParameterDistinct(type2, extendsBoundClass);
}
if (superBoundClass instanceof PsiTypeParameter) return false;
return !superBoundClass.isInheritor(extendsBoundClass, true);
}
return true;
}
return !type1.equals(type2);
}
private static boolean try2ProveTypeParameterDistinct(PsiType type, PsiClass typeParameter) {
final PsiClassType[] types = typeParameter.getExtendsListTypes();
if (types.length == 0) return false;
return provablyDistinct(PsiWildcardType.createExtends(typeParameter.getManager(), types[0]), type);
}
public static boolean isPrimitiveAndNotNull(PsiType type) {
return type instanceof PsiPrimitiveType && !isNullType(type);
}