CanSealedSubClassBeObjectInspection: don't report if sub-class has classModifier

#KT-38790 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-05-13 06:39:08 +09:00
committed by Yan Zhulanow
parent cea879cbd5
commit 3272b8fc2c
7 changed files with 67 additions and 2 deletions
@@ -46,6 +46,7 @@ class CanSealedSubClassBeObjectInspection : AbstractKotlinInspection() {
val candidates = klass.getSubclasses()
.withEmptyConstructors()
.thatHasNoClassModifiers()
.thatAreFinal()
.thatHasNoTypeParameters()
.thatHasNoInnerClasses()
@@ -80,6 +81,13 @@ class CanSealedSubClassBeObjectInspection : AbstractKotlinInspection() {
.filter { klass -> klass.secondaryConstructors.all { cons -> cons.valueParameters.isEmpty() } }.toList()
}
private fun List<KtClass>.thatHasNoClassModifiers(): List<KtClass> {
return filter { klass ->
val modifierList = klass.modifierList ?: return@filter true
CLASS_MODIFIERS.none { modifierList.hasModifier(it) }
}
}
private fun List<KtClass>.thatHasNoCompanionObjects(): List<KtClass> {
return filter { klass -> klass.companionObjects.isEmpty() }
}
@@ -110,7 +118,7 @@ class CanSealedSubClassBeObjectInspection : AbstractKotlinInspection() {
private fun KtClass.hasNoStateOrEquals(): Boolean {
if (primaryConstructor?.valueParameters?.isNotEmpty() == true) return false
val body = getBody()
val body = body
return body == null || run {
val declarations = body.declarations
declarations.asSequence().filterIsInstance<KtProperty>().none { property ->
@@ -132,7 +140,7 @@ class CanSealedSubClassBeObjectInspection : AbstractKotlinInspection() {
}
private fun KtClass.hasNoInnerClass(): Boolean {
val internalClasses = getBody()
val internalClasses = body
?.declarations
?.filterIsInstance<KtClass>() ?: return true
@@ -143,5 +151,13 @@ class CanSealedSubClassBeObjectInspection : AbstractKotlinInspection() {
val EQUALS = OperatorNameConventions.EQUALS.asString()
const val HASH_CODE = "hashCode"
val CLASS_MODIFIERS = listOf(
KtTokens.ANNOTATION_KEYWORD,
KtTokens.DATA_KEYWORD,
KtTokens.ENUM_KEYWORD,
KtTokens.INNER_KEYWORD,
KtTokens.SEALED_KEYWORD,
)
}
}
@@ -0,0 +1,5 @@
// PROBLEM: none
// DISABLE-ERRORS
sealed class Bar
annotation <caret>class Foo : Bar()
@@ -0,0 +1,5 @@
// PROBLEM: none
// DISABLE-ERRORS
sealed class Bar
data <caret>class Foo : Bar()
@@ -0,0 +1,5 @@
// PROBLEM: none
// DISABLE-ERRORS
sealed class Bar
enum <caret>class Foo : Bar()
@@ -0,0 +1,5 @@
// PROBLEM: none
// DISABLE-ERRORS
sealed class Bar
inner <caret>class Foo : Bar()
@@ -0,0 +1,4 @@
// PROBLEM: none
sealed class Bar
sealed <caret>class Foo : Bar()
@@ -3385,6 +3385,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/inspectionsLocal/convertSealedSubClassToObject"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
}
@TestMetadata("annotation.kt")
public void testAnnotation() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/annotation.kt");
}
@TestMetadata("baseEquals.kt")
public void testBaseEquals() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/baseEquals.kt");
@@ -3415,6 +3420,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/convertSubClassWithoutParentheses.kt");
}
@TestMetadata("data.kt")
public void testData() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/data.kt");
}
@TestMetadata("enum.kt")
public void testEnum() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/enum.kt");
}
@TestMetadata("fakeState.kt")
public void testFakeState() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/fakeState.kt");
@@ -3425,6 +3440,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/generic.kt");
}
@TestMetadata("inner.kt")
public void testInner() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/inner.kt");
}
@TestMetadata("noEquals.kt")
public void testNoEquals() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/noEquals.kt");
@@ -3450,6 +3470,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/ownState.kt");
}
@TestMetadata("sealed.kt")
public void testSealed() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/sealed.kt");
}
@TestMetadata("sealedEquals.kt")
public void testSealedEquals() throws Exception {
runTest("idea/testData/inspectionsLocal/convertSealedSubClassToObject/sealedEquals.kt");