java sealed types: ensure sealed class inheritors are sealed/non-sealed/final (IDEA-243536)

GitOrigin-RevId: 768635cd8a1b237893429ac1882296de8477536d
This commit is contained in:
Anna Kozlova
2020-06-16 00:04:16 +03:00
committed by intellij-monorepo-bot
parent 7c64f7f035
commit 1b944210ef
4 changed files with 19 additions and 2 deletions
@@ -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)) {
@@ -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));
}
@@ -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
@@ -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 <error descr="sealed, non-sealed or final modifiers expected">E</error> extends A {}
<error descr="Illegal combination of modifiers: 'sealed' and 'sealed'">sealed</error> <error descr="Illegal combination of modifiers: 'sealed' and 'sealed'">sealed</error> class SealedSealed {}
<error descr="Illegal combination of modifiers: 'sealed' and 'non-sealed'">sealed</error> <error descr="Illegal combination of modifiers: 'non-sealed' and 'sealed'">non-sealed</error> class SealedNonSealed {}
<error descr="Illegal combination of modifiers: 'sealed' and 'final'">sealed</error> <error descr="Illegal combination of modifiers: 'final' and 'sealed'">final</error> 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 <error descr="sealed, non-sealed or final modifiers expected">ICSameFile</error> implements IC {}
sealed interface ID0 {}
non-sealed interface ID1 extends ID0 {}