From 1b944210ef4cbf62eabaa215a661ec3754dba28b Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 15 Jun 2020 22:22:24 +0200 Subject: [PATCH] java sealed types: ensure sealed class inheritors are sealed/non-sealed/final (IDEA-243536) GitOrigin-RevId: 768635cd8a1b237893429ac1882296de8477536d --- .../daemon/impl/analysis/HighlightClassUtil.java | 15 +++++++++++++++ .../impl/analysis/HighlightVisitorImpl.java | 1 + .../src/messages/JavaErrorBundle.properties | 1 + .../SealedTypesBasics.java | 4 ++-- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java index b6bc792de8f6..bbc9974f83db 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightClassUtil.java @@ -947,6 +947,21 @@ public class HighlightClassUtil { } return null; } + + public static HighlightInfo checkWellFormedSealedInheritor(PsiClass psiClass) { + if (!psiClass.hasModifierProperty(PsiModifier.SEALED) && + !psiClass.hasModifierProperty(PsiModifier.NON_SEALED) && + !psiClass.hasModifierProperty(PsiModifier.FINAL)) { + PsiIdentifier nameIdentifier = psiClass.getNameIdentifier(); + if (nameIdentifier == null) return null; + if (Arrays.stream(psiClass.getSuperTypes()).map(superType -> superType.resolve()) + .anyMatch(superClass -> superClass != null && superClass.hasModifierProperty(PsiModifier.SEALED))) { + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(nameIdentifier) + .descriptionAndTooltip(JavaErrorBundle.message("sealed.type.inheritor.expected.modifiers", PsiModifier.SEALED, PsiModifier.NON_SEALED, PsiModifier.FINAL)).create(); + } + } + return null; + } public static HighlightInfo checkIllegalInstanceMemberInRecord(PsiMember member) { if (!member.hasModifierProperty(PsiModifier.STATIC)) { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 8da9df41d8c4..5d1f10d4fbd3 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -472,6 +472,7 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkClassAndPackageConflict(aClass)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkPublicClassInRightFile(aClass)); if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkWellFormedRecord(aClass)); + if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkWellFormedSealedInheritor(aClass)); if (!myHolder.hasErrorResults()) myHolder.add(GenericsHighlightUtil.checkTypeParameterOverrideEquivalentMethods(aClass, myLanguageLevel)); } diff --git a/java/java-psi-impl/src/messages/JavaErrorBundle.properties b/java/java-psi-impl/src/messages/JavaErrorBundle.properties index dec8db70378f..aa9db7ae1e61 100644 --- a/java/java-psi-impl/src/messages/JavaErrorBundle.properties +++ b/java/java-psi-impl/src/messages/JavaErrorBundle.properties @@ -465,3 +465,4 @@ bad.type.in.switch.expression=Bad type in switch expression: {0} cannot be conve switch.expression.cannot.be.void=Target type for switch expression cannot be void annotation.on.static.member.qualifying.type.family.name=Move type annotation functional.interface.must.not.be.sealed.error.description=Functional interface can''t be declared as ''{0}'' +sealed.type.inheritor.expected.modifiers={0}, {1} or {2} modifiers expected diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedTypesBasics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedTypesBasics.java index 58c1bdbcb5fe..9ce1b21f2448 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedTypesBasics.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedTypesBasics.java @@ -3,7 +3,7 @@ sealed class A permits B {} sealed class B extends A permits C, D {} final class C extends B {} non-sealed class D extends B {} -class E extends A {} +class E extends A {} sealed sealed class SealedSealed {} sealed non-sealed class SealedNonSealed {} sealed final class SealedFinal {} @@ -12,7 +12,7 @@ class E extends A {} sealed interface IA permits IB, IC {} final class IB implements IA {} sealed interface IC extends IA {} -class ICSameFile implements IC {} +class ICSameFile implements IC {} sealed interface ID0 {} non-sealed interface ID1 extends ID0 {}