KTIJ-717 [Java side inspection]: "implementation of Kotlin sealed"
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This inspection reports attempt to inherit Kotlin sealed interface/class in Java code.
|
||||
</body>
|
||||
</html>
|
||||
@@ -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
|
||||
|
||||
@@ -1504,6 +1504,14 @@
|
||||
language="JAVA"
|
||||
key="inspection.kotlin.internal.in.java.display.name" bundle="messages.KotlinBundle"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.KotlinSealedInheritorsInJavaInspection"
|
||||
groupPath="Kotlin"
|
||||
groupName="Java interop issues"
|
||||
enabledByDefault="true"
|
||||
level="ERROR"
|
||||
language="JAVA"
|
||||
key="inspection.kotlin.sealed.in.java.display.name" bundle="messages.KotlinBundle"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.inspections.MoveSuspiciousCallableReferenceIntoParenthesesInspection"
|
||||
groupPath="Kotlin"
|
||||
groupName="Probable bugs"
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.inspections
|
||||
|
||||
import com.intellij.codeInspection.LocalInspectionTool
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.source.PsiClassReferenceType
|
||||
import org.jetbrains.kotlin.asJava.classes.KtUltraLightClass
|
||||
import org.jetbrains.kotlin.descriptors.isSealed
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
|
||||
|
||||
class KotlinSealedInheritorsInJavaInspection : LocalInspectionTool() {
|
||||
companion object {
|
||||
private fun PsiClass.listSealedParentReferences(): List<PsiReference> {
|
||||
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<PsiReference>? = 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+18
@@ -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() {};
|
||||
}
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
sealed interface KotlinSealedInterface
|
||||
sealed class KotlinSealedClass
|
||||
|
||||
interface KotlinInterface: KotlinSealedInterface
|
||||
class KotlinClass: KotlinSealedClass()
|
||||
@@ -0,0 +1,72 @@
|
||||
<problems>
|
||||
<problem>
|
||||
<file>JavaTriesToExtendKotlinSealed.java</file>
|
||||
<line>3</line>
|
||||
<module>testKotlinSealedInJavaTest_KotlinSealedInJavaTest</module>
|
||||
<package><default></package>
|
||||
<entry_point TYPE="class" FQNAME="JavaTriesToExtendKotlinSealed.TryToImplement"/>
|
||||
<problem_class id="KotlinSealedInheritorsInJava" severity="ERROR" attribute_key="ERRORS_ATTRIBUTES">Inheritance of Kotlin sealed
|
||||
interface/class from Java
|
||||
</problem_class>
|
||||
<description>Java class cannot be a part of Kotlin sealed hierarchy</description>
|
||||
<highlighted_element>KotlinSealedInterface</highlighted_element>
|
||||
<offset>4</offset>
|
||||
<length>71</length>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>JavaTriesToExtendKotlinSealed.java</file>
|
||||
<line>4</line>
|
||||
<module>testKotlinSealedInJavaTest_KotlinSealedInJavaTest</module>
|
||||
<package><default></package>
|
||||
<entry_point TYPE="class" FQNAME="JavaTriesToExtendKotlinSealed.TryToExtend"/>
|
||||
<problem_class id="KotlinSealedInheritorsInJava" severity="ERROR" attribute_key="ERRORS_ATTRIBUTES">Inheritance of Kotlin sealed
|
||||
interface/class from Java
|
||||
</problem_class>
|
||||
<description>Java interface cannot be a part of Kotlin sealed hierarchy</description>
|
||||
<highlighted_element>KotlinSealedInterface</highlighted_element>
|
||||
<offset>4</offset>
|
||||
<length>69</length>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>JavaTriesToExtendKotlinSealed.java</file>
|
||||
<line>5</line>
|
||||
<module>testKotlinSealedInJavaTest_KotlinSealedInJavaTest</module>
|
||||
<package><default></package>
|
||||
<entry_point TYPE="class" FQNAME="JavaTriesToExtendKotlinSealed.TryToExtendClass"/>
|
||||
<problem_class id="KotlinSealedInheritorsInJava" severity="ERROR" attribute_key="ERRORS_ATTRIBUTES">Inheritance of Kotlin sealed
|
||||
interface/class from Java
|
||||
</problem_class>
|
||||
<description>Java class cannot be a part of Kotlin sealed hierarchy</description>
|
||||
<highlighted_element>KotlinSealedClass</highlighted_element>
|
||||
<offset>4</offset>
|
||||
<length>66</length>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>JavaTriesToExtendKotlinSealed.java</file>
|
||||
<line>12</line>
|
||||
<module>testKotlinSealedInJavaTest_KotlinSealedInJavaTest</module>
|
||||
<package><default></package>
|
||||
<entry_point TYPE="class" FQNAME="JavaTriesToExtendKotlinSealed$1" />
|
||||
<problem_class id="KotlinSealedInheritorsInJava" severity="ERROR" attribute_key="ERRORS_ATTRIBUTES">Inheritance of Kotlin sealed interface/class from Java</problem_class>
|
||||
<description>Java class cannot be a part of Kotlin sealed hierarchy</description>
|
||||
<highlighted_element>KotlinSealedInterface</highlighted_element>
|
||||
<offset>52</offset>
|
||||
<length>26</length>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>JavaTriesToExtendKotlinSealed.java</file>
|
||||
<line>13</line>
|
||||
<module>testKotlinSealedInJavaTest_KotlinSealedInJavaTest</module>
|
||||
<package><default></package>
|
||||
<entry_point TYPE="class" FQNAME="JavaTriesToExtendKotlinSealed$2" />
|
||||
<problem_class id="KotlinSealedInheritorsInJava" severity="ERROR" attribute_key="ERRORS_ATTRIBUTES">Inheritance of Kotlin sealed interface/class from Java</problem_class>
|
||||
<description>Java class cannot be a part of Kotlin sealed hierarchy</description>
|
||||
<highlighted_element>KotlinSealedClass()</highlighted_element>
|
||||
<offset>44</offset>
|
||||
<length>22</length>
|
||||
</problem>
|
||||
</problems>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"inspectionClass": "org.jetbrains.kotlin.idea.inspections.KotlinSealedInheritorsInJavaInspection"
|
||||
}
|
||||
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user