diff --git a/idea/resources-en/inspectionDescriptions/KotlinSealedInheritorsInJava.html b/idea/resources-en/inspectionDescriptions/KotlinSealedInheritorsInJava.html
new file mode 100644
index 00000000000..a81e027b794
--- /dev/null
+++ b/idea/resources-en/inspectionDescriptions/KotlinSealedInheritorsInJava.html
@@ -0,0 +1,5 @@
+
+
+This inspection reports attempt to inherit Kotlin sealed interface/class in Java code.
+
+
\ No newline at end of file
diff --git a/idea/resources-en/messages/KotlinBundle.properties b/idea/resources-en/messages/KotlinBundle.properties
index 8503a39be15..a5b57965757 100644
--- a/idea/resources-en/messages/KotlinBundle.properties
+++ b/idea/resources-en/messages/KotlinBundle.properties
@@ -1343,6 +1343,7 @@ double.negation.fix.text=Remove redundant negations
redundant.double.negation=Redundant double negation
equals.between.objects.of.inconvertible.types='equals()' between objects of inconvertible types
usage.of.kotlin.internal.declaration.from.different.module=Usage of Kotlin internal declaration from different module
+inheritance.of.kotlin.sealed=Java {0,choice,0#interface|1#class} cannot be a part of Kotlin sealed hierarchy
junit.static.methods=JUnit static methods
redundant.override.fix.text=Remove redundant overriding method
redundant.overriding.method=Redundant overriding method
@@ -2064,6 +2065,7 @@ inspection.replace.array.of.with.literal.display.name='arrayOf' call can be repl
inspection.copy.without.named.arguments.display.name='copy' method of data class is called without named arguments
inspection.move.suspicious.callable.reference.into.parentheses.display.name=Suspicious callable reference used as lambda result
inspection.kotlin.internal.in.java.display.name=Usage of Kotlin internal declarations from Java
+inspection.kotlin.sealed.in.java.display.name=Inheritance of Kotlin sealed interface/class from Java
inspection.unused.lambda.expression.body.display.name=Unused return value of a function with lambda expression body
inspection.destructuring.wrong.name.display.name=Variable in destructuring declaration uses name of a wrong data class property
inspection.data.class.private.constructor.display.name=Private data class constructor is exposed via the 'copy' method
diff --git a/idea/resources/META-INF/inspections.xml b/idea/resources/META-INF/inspections.xml
index eb699fcedf2..4717ddc6426 100644
--- a/idea/resources/META-INF/inspections.xml
+++ b/idea/resources/META-INF/inspections.xml
@@ -1504,6 +1504,14 @@
language="JAVA"
key="inspection.kotlin.internal.in.java.display.name" bundle="messages.KotlinBundle"/>
+
+
{
+ if (this is PsiAnonymousClass && baseClassType.isKotlinSealed())
+ return listOf(baseClassReference)
+
+ val sealedBaseClasses = extendsList?.listSealedMembers()
+ val sealedBaseInterfaces = implementsList?.listSealedMembers()
+
+ return sealedBaseClasses.orEmpty() + sealedBaseInterfaces.orEmpty()
+ }
+
+ private fun PsiReferenceList.listSealedMembers(): List? = referencedTypes
+ ?.filter { it.isKotlinSealed() }
+ ?.mapNotNull { it as? PsiClassReferenceType }
+ ?.map { it.reference }
+
+ private fun PsiClassType.isKotlinSealed(): Boolean = resolve()?.isKotlinSealed() == true
+
+ private fun PsiClass.isKotlinSealed(): Boolean = this is KtUltraLightClass && getDescriptor()?.isSealed() == true
+
+ private val PsiClass.abstractionTypeName: String
+ get() = if (isInterface) "interface" else "class"
+ }
+
+ override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
+ return object : JavaElementVisitor() {
+ override fun visitClass(aClass: PsiClass?) {
+ aClass?.listSealedParentReferences()?.forEach {
+ holder.registerProblem(
+ it, KotlinBundle.message("inheritance.of.kotlin.sealed", 0.takeIf { aClass.isInterface } ?: 1),
+ ProblemHighlightType.GENERIC_ERROR_OR_WARNING
+ )
+ }
+ }
+
+ override fun visitAnonymousClass(aClass: PsiAnonymousClass?) = visitClass(aClass)
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinSealedInJavaTest/before/JavaTriesToExtendKotlinSealed.java b/idea/testData/multiFileInspections/kotlinSealedInJavaTest/before/JavaTriesToExtendKotlinSealed.java
new file mode 100644
index 00000000000..2ab7d257214
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinSealedInJavaTest/before/JavaTriesToExtendKotlinSealed.java
@@ -0,0 +1,18 @@
+public class JavaTriesToExtendKotlinSealed {
+
+ private static class TryToImplement implements KotlinSealedInterface {}
+ private static interface TryToExtend extends KotlinSealedInterface {}
+ private static class TryToExtendClass extends KotlinSealedClass {}
+
+ class OkToImplement implements KotlinInterface {}
+ interface OkToExtend extends KotlinInterface {}
+ class OkToExtendClass extends KotlinClass{}
+
+ public static void main(String[] args) {
+ KotlinSealedInterface sealedInterface = new KotlinSealedInterface() {}; // anonymouns class implements interface
+ KotlinSealedClass sealedClass = new KotlinSealedClass() {};
+
+ new KotlinInterface() {};
+ new KotlinClass() {};
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinSealedInJavaTest/before/KotlinSealedDeclarations.kt b/idea/testData/multiFileInspections/kotlinSealedInJavaTest/before/KotlinSealedDeclarations.kt
new file mode 100644
index 00000000000..7e9097cee71
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinSealedInJavaTest/before/KotlinSealedDeclarations.kt
@@ -0,0 +1,5 @@
+sealed interface KotlinSealedInterface
+sealed class KotlinSealedClass
+
+interface KotlinInterface: KotlinSealedInterface
+class KotlinClass: KotlinSealedClass()
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinSealedInJavaTest/expected.xml b/idea/testData/multiFileInspections/kotlinSealedInJavaTest/expected.xml
new file mode 100644
index 00000000000..585da3710b0
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinSealedInJavaTest/expected.xml
@@ -0,0 +1,72 @@
+
+
+ JavaTriesToExtendKotlinSealed.java
+ 3
+ testKotlinSealedInJavaTest_KotlinSealedInJavaTest
+ <default>
+
+ Inheritance of Kotlin sealed
+ interface/class from Java
+
+ Java class cannot be a part of Kotlin sealed hierarchy
+ KotlinSealedInterface
+ 4
+ 71
+
+
+
+ JavaTriesToExtendKotlinSealed.java
+ 4
+ testKotlinSealedInJavaTest_KotlinSealedInJavaTest
+ <default>
+
+ Inheritance of Kotlin sealed
+ interface/class from Java
+
+ Java interface cannot be a part of Kotlin sealed hierarchy
+ KotlinSealedInterface
+ 4
+ 69
+
+
+
+ JavaTriesToExtendKotlinSealed.java
+ 5
+ testKotlinSealedInJavaTest_KotlinSealedInJavaTest
+ <default>
+
+ Inheritance of Kotlin sealed
+ interface/class from Java
+
+ Java class cannot be a part of Kotlin sealed hierarchy
+ KotlinSealedClass
+ 4
+ 66
+
+
+
+ JavaTriesToExtendKotlinSealed.java
+ 12
+ testKotlinSealedInJavaTest_KotlinSealedInJavaTest
+ <default>
+
+ Inheritance of Kotlin sealed interface/class from Java
+ Java class cannot be a part of Kotlin sealed hierarchy
+ KotlinSealedInterface
+ 52
+ 26
+
+
+
+ JavaTriesToExtendKotlinSealed.java
+ 13
+ testKotlinSealedInJavaTest_KotlinSealedInJavaTest
+ <default>
+
+ Inheritance of Kotlin sealed interface/class from Java
+ Java class cannot be a part of Kotlin sealed hierarchy
+ KotlinSealedClass()
+ 44
+ 22
+
+
\ No newline at end of file
diff --git a/idea/testData/multiFileInspections/kotlinSealedInJavaTest/kotlinSealedInJavaTest.test b/idea/testData/multiFileInspections/kotlinSealedInJavaTest/kotlinSealedInJavaTest.test
new file mode 100644
index 00000000000..ef7ba9896b7
--- /dev/null
+++ b/idea/testData/multiFileInspections/kotlinSealedInJavaTest/kotlinSealedInJavaTest.test
@@ -0,0 +1,3 @@
+{
+ "inspectionClass": "org.jetbrains.kotlin.idea.inspections.KotlinSealedInheritorsInJavaInspection"
+}
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
index 8c893b2d52e..edc26e85601 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/MultiFileInspectionTestGenerated.java
@@ -49,6 +49,11 @@ public class MultiFileInspectionTestGenerated extends AbstractMultiFileInspectio
runTest("idea/testData/multiFileInspections/kotlinInternalInJavaTest/kotlinInternalInJavaTest.test");
}
+ @TestMetadata("kotlinSealedInJavaTest/kotlinSealedInJavaTest.test")
+ public void testKotlinSealedInJavaTest_KotlinSealedInJavaTest() throws Exception {
+ runTest("idea/testData/multiFileInspections/kotlinSealedInJavaTest/kotlinSealedInJavaTest.test");
+ }
+
@TestMetadata("mainInTwoModules/mainInTwoModules.test")
public void testMainInTwoModules_MainInTwoModules() throws Exception {
runTest("idea/testData/multiFileInspections/mainInTwoModules/mainInTwoModules.test");