ConvertObjectToDataObjectInspection: convert not stateless objects too

KTIJ-22087
https://jetbrains.team/p/ij/reviews/95181
https://jetbrains.team/p/ij/reviews/95344

GitOrigin-RevId: 24b28366bc1a800354f63f0a5744c2777078d8bf
This commit is contained in:
Nikita Bobko
2022-09-22 20:16:31 +00:00
committed by intellij-monorepo-bot
parent 9e197c6d81
commit fbada819f2
5 changed files with 28 additions and 6 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClass
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -85,12 +86,17 @@ class CanSealedSubClassBeObjectInspection : AbstractKotlinInspection() {
&& hasNoStateOrEquals()
}
fun KtClassOrObject.isSubclassOfStatelessSealed(): Boolean {
fun KtSuperTypeListEntry.asKtClass(): KtClass? = typeAsUserType?.referenceExpression?.mainReference?.resolve() as? KtClass
return superTypeListEntries.asSequence().mapNotNull { it.asKtClass() }.any {
private fun KtClassOrObject.isSubclassOfStatelessSealed(): Boolean =
superTypeListEntries.asSequence().mapNotNull { it.asKtClass() }.any {
it.isSealed() && it.hasNoStateOrEquals() && it.baseClassHasNoStateOrEquals()
}
}
fun KtSuperTypeListEntry.asKtClass(): KtClass? =
when (val resolved = typeAsUserType?.referenceExpression?.mainReference?.resolve()) {
is KtConstructor<*> -> resolved.containingClass()
is KtClass -> resolved
else -> null
}
private fun KtClass.withEmptyConstructors(): Boolean =
primaryConstructorParameters.isEmpty() && secondaryConstructors.all { it.valueParameters.isEmpty() }
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.codeinsight.api.classic.inspections.AbstractKotlinInspection
import org.jetbrains.kotlin.idea.core.resolveType
import org.jetbrains.kotlin.idea.inspections.CanSealedSubClassBeObjectInspection.Companion.isSubclassOfStatelessSealed
import org.jetbrains.kotlin.idea.inspections.CanSealedSubClassBeObjectInspection.Companion.asKtClass
import org.jetbrains.kotlin.idea.inspections.VirtualFunction.*
import org.jetbrains.kotlin.idea.inspections.VirtualFunction.Function
import org.jetbrains.kotlin.idea.intentions.conventionNameCalls.*
@@ -56,7 +56,7 @@ class ConvertObjectToDataObjectInspection : AbstractKotlinInspection() {
val isSerializable = isSerializable(ktObject)
val toString = ktObject.findToString()
val isSerializableCase = toString == TrivialSuper && isSerializable
val isSealedSubClassCase by lazy { toString == TrivialSuper && ktObject.isSubclassOfStatelessSealed() }
val isSealedSubClassCase by lazy { toString == TrivialSuper && ktObject.isSubclassOfSealed() }
val isToStringCase by lazy { toString is Function && isCompatibleToString(ktObject, fqName, toString.function) }
if ((isSerializableCase || isSealedSubClassCase || isToStringCase) &&
isCompatibleHashCode(ktObject) &&
@@ -79,6 +79,9 @@ class ConvertObjectToDataObjectInspection : AbstractKotlinInspection() {
}
}
private fun KtObjectDeclaration.isSubclassOfSealed(): Boolean =
superTypeListEntries.asSequence().mapNotNull { it.asKtClass() }.any { it.isSealed() }
private fun isSerializable(ktObject: KtObjectDeclaration): Boolean =
ktObject.resolveToDescriptorIfAny()
?.getAllSuperClassifiers()
@@ -3932,6 +3932,11 @@ public abstract class LocalInspectionTestGenerated extends AbstractLocalInspecti
runTest("testData/inspectionsLocal/convertObjectToDataObject/publicReadResolve.kt");
}
@TestMetadata("sealedNotStatelessSubObject.kt")
public void testSealedNotStatelessSubObject() throws Exception {
runTest("testData/inspectionsLocal/convertObjectToDataObject/sealedNotStatelessSubObject.kt");
}
@TestMetadata("sealedSubObject.kt")
public void testSealedSubObject() throws Exception {
runTest("testData/inspectionsLocal/convertObjectToDataObject/sealedSubObject.kt");
@@ -0,0 +1,4 @@
// COMPILER_ARGUMENTS: -XXLanguage:+DataObjects
sealed class Seal(val x: Int)
object<caret> Foo : Seal(1)
@@ -0,0 +1,4 @@
// COMPILER_ARGUMENTS: -XXLanguage:+DataObjects
sealed class Seal(val x: Int)
data object Foo : Seal(1)