From d691432ee60eb41bb90a596dcab54534be75c399 Mon Sep 17 00:00:00 2001 From: Artemiy Sartakov Date: Thu, 18 Feb 2021 16:41:27 +0700 Subject: [PATCH] Sealed classes: fixed type conversion check for deep sealed hierarchy GitOrigin-RevId: b70a5ddf84cada4dc8efd29c8ed4090d42672b55 --- .../com/intellij/psi/util/TypeConversionUtil.java | 11 +++++++---- .../advHighlightingSealedTypes/SealedClassCast.java | 12 ++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java index 2fb00435eb77..be3c641c08c0 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/TypeConversionUtil.java @@ -353,13 +353,16 @@ public final class TypeConversionUtil { *

See JEP-397 for more details.

*/ 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 visited) { + private static boolean canConvertSealedTo(@NotNull PsiClass sealedClass, + @NotNull PsiClass psiClass, + @NotNull Set 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 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 findDirectSubClassesInFile(@NotNull PsiClass sealedClass) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedClassCast.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedClassCast.java index 5c7bda5f554c..5e1e327ee862 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedClassCast.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedClassCast.java @@ -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 (a instanceof Foo) 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 (gp instanceof RandomClass) { + System.out.println("It's a RandomClass"); + } + } } \ No newline at end of file