Sealed classes: fixed type conversion check for deep sealed hierarchy

GitOrigin-RevId: b70a5ddf84cada4dc8efd29c8ed4090d42672b55
This commit is contained in:
Artemiy Sartakov
2021-02-18 10:44:34 +00:00
committed by intellij-monorepo-bot
parent 3042bfaaba
commit d691432ee6
2 changed files with 19 additions and 4 deletions
@@ -353,13 +353,16 @@ public final class TypeConversionUtil {
* <p>See JEP-397 for more details.</p>
*/
public static boolean canConvertSealedTo(@NotNull PsiClass sealedClass, @NotNull PsiClass psiClass) {
return canConvertSealedTo(sealedClass, psiClass, new HashSet<>());
return canConvertSealedTo(sealedClass, psiClass, new HashSet<>(), true);
}
private static boolean canConvertSealedTo(@NotNull PsiClass sealedClass, @NotNull PsiClass psiClass, @NotNull Set<PsiClass> visited) {
private static boolean canConvertSealedTo(@NotNull PsiClass sealedClass,
@NotNull PsiClass psiClass,
@NotNull Set<PsiClass> visited,
boolean isTopLevel) {
if (visited.contains(sealedClass)) return true;
visited.add(sealedClass);
if (!sealedClass.isInterface() && !psiClass.isInterface()) return true;
if (isTopLevel && !sealedClass.isInterface() && !psiClass.isInterface()) return true;
PsiReferenceList permitsList = sealedClass.getPermitsList();
List<PsiClass> sealedSubClasses = new SmartList<>();
boolean hasClassInheritors;
@@ -372,7 +375,7 @@ public final class TypeConversionUtil {
.map(t -> t.resolve())
.anyMatch(subClass -> subClassExtendsClass(subClass, psiClass, sealedSubClasses));
}
return hasClassInheritors || sealedSubClasses.stream().anyMatch(subClass -> canConvertSealedTo(subClass, psiClass, visited));
return hasClassInheritors || sealedSubClasses.stream().anyMatch(subClass -> canConvertSealedTo(subClass, psiClass, visited, false));
}
private static @NotNull Set<PsiClass> findDirectSubClassesInFile(@NotNull PsiClass sealedClass) {
@@ -37,6 +37,12 @@ interface Foo {
interface I1 {}
sealed interface GrandParent permits Parent {}
static sealed class Parent implements GrandParent permits Child {}
static final class Child extends Parent {}
static class RandomClass {}
static void testA(A a) {
if (<error descr="Inconvertible types; cannot cast 'Foo.A' to 'Foo'">a instanceof Foo</error>)
System.out.println("It's a Foo");
@@ -85,4 +91,10 @@ interface Foo {
static void testRecursive1(Recursive1 r1) {
if (r1 instanceof I1) {}
}
static void testDeepSealedHierarchy(GrandParent gp) {
if (<error descr="Inconvertible types; cannot cast 'Foo.GrandParent' to 'Foo.RandomClass'">gp instanceof RandomClass</error>) {
System.out.println("It's a RandomClass");
}
}
}