From 7d2384271f06d4d723bbf0463ece73e4066d621e Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 16 Jun 2020 08:38:40 +0200 Subject: [PATCH] java sealed types: check sealed class inheritors (IDEA-243536) GitOrigin-RevId: 0390d8db04b10b8d5c1206987877d6356a93d535 --- .../impl/analysis/HighlightClassUtil.java | 24 +++++++++++++++++++ .../daemon/impl/analysis/HighlightUtil.java | 3 +++ .../src/messages/JavaErrorBundle.properties | 1 + .../SealedTypesBasics.java | 2 +- 4 files changed, 29 insertions(+), 1 deletion(-) 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 7c76a792220a..f85afa0270d8 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 @@ -1012,4 +1012,28 @@ public class HighlightClassUtil { } return null; } + + static HighlightInfo checkExtendsSealedClass(PsiClass aClass, PsiClass superClass, PsiJavaCodeReferenceElement elementToHighlight) { + if (superClass.hasModifierProperty(PsiModifier.SEALED)) { + PsiClassType[] permittedTypes = superClass.getPermitsListTypes(); + if (permittedTypes.length > 0) { + if (Arrays.stream(permittedTypes).map(permittedType -> permittedType.resolve()).anyMatch(permittedClass -> aClass.equals(permittedClass))) { + return null; + } + } + else if (JavaPsiFacade.getInstance(aClass.getProject()).arePackagesTheSame(aClass, superClass)) { + return null; + } + else { + PsiJavaModule javaModule = JavaModuleGraphUtil.findDescriptorByElement(aClass); + if (javaModule != null && javaModule == JavaModuleGraphUtil.findDescriptorByElement(superClass)) { + return null; + } + } + return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR) + .descriptionAndTooltip(JavaErrorBundle.message("not.allowed.in.sealed.hierarchy", aClass.getName())) + .range(elementToHighlight).create(); + } + return null; + } } diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index 512b2f1c916c..e02efb254839 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -3153,6 +3153,9 @@ public class HighlightUtil { if (highlightInfo == null) { highlightInfo = GenericsHighlightUtil.checkCannotInheritFromTypeParameter(aClass, ref); } + if (highlightInfo == null) { + highlightInfo = HighlightClassUtil.checkExtendsSealedClass((PsiClass)refGrandParent, aClass, ref); + } } } else if (refGrandParent instanceof PsiMethod && ((PsiMethod)refGrandParent).getThrowsList() == referenceList) { diff --git a/java/java-psi-impl/src/messages/JavaErrorBundle.properties b/java/java-psi-impl/src/messages/JavaErrorBundle.properties index e5ce278d1dc7..ba34d1e2b5bd 100644 --- a/java/java-psi-impl/src/messages/JavaErrorBundle.properties +++ b/java/java-psi-impl/src/messages/JavaErrorBundle.properties @@ -476,3 +476,4 @@ type.parameter.has.incompatible.upper.bounds=Type parameter {0} has incompatible safevarargs.not.allowed.on.methods.with.fixed.arity=@SafeVarargs is not allowed on methods with fixed arity 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 +not.allowed.in.sealed.hierarchy={0} is not allowed in the sealed hierarchy diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedTypesBasics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlightingSealedTypes/SealedTypesBasics.java index 9ce1b21f2448..5a8a3c18f3a0 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 {}