From 0b9106b0f89986ef46315f20ff6fc7fbb34e1b0a Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Tue, 4 Feb 2020 13:46:28 +0900 Subject: [PATCH] CanBePrimaryConstructorPropertyInspection: do not report for 'open' property used in class initializer in 'open' class --- ...nBePrimaryConstructorPropertyInspection.kt | 27 ++++++++--- .../inspectionData/expected.xml | 24 ++++++++++ .../properties.kt | 47 ++++++++++++++++++- 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/CanBePrimaryConstructorPropertyInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/CanBePrimaryConstructorPropertyInspection.kt index c1ea0cb4ef2..cd99105b364 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/CanBePrimaryConstructorPropertyInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/CanBePrimaryConstructorPropertyInspection.kt @@ -12,13 +12,14 @@ import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.intentions.MovePropertyToConstructorIntention +import org.jetbrains.kotlin.idea.intentions.loopToCallChain.hasUsages import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.psi.KtReferenceExpression -import org.jetbrains.kotlin.psi.propertyVisitor +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull class CanBePrimaryConstructorPropertyInspection : AbstractKotlinInspection() { @@ -42,9 +43,14 @@ class CanBePrimaryConstructorPropertyInspection : AbstractKotlinInspection() { if (nameIdentifier.text != assignedDescriptor.name.asString()) return val assignedParameter = DescriptorToSourceUtils.descriptorToDeclaration(assignedDescriptor) as? KtParameter ?: return - if (property.containingClassOrObject !== assignedParameter.containingClassOrObject) return - - if (property.containingClassOrObject?.isInterfaceClass() == true) return + val containingClassOrObject = property.containingClassOrObject ?: return + if (containingClassOrObject !== assignedParameter.containingClassOrObject) return + if (containingClassOrObject.isInterfaceClass()) return + if (property.hasModifier(KtTokens.OPEN_KEYWORD) + && containingClassOrObject is KtClass + && containingClassOrObject.isOpen() + && assignedParameter.isUsedInClassInitializer(containingClassOrObject) + ) return holder.registerProblem( holder.manager.createProblemDescriptor( @@ -58,4 +64,13 @@ class CanBePrimaryConstructorPropertyInspection : AbstractKotlinInspection() { ) }) } + + private fun KtClass.isOpen(): Boolean { + return hasModifier(KtTokens.OPEN_KEYWORD) || hasModifier(KtTokens.ABSTRACT_KEYWORD) || hasModifier(KtTokens.SEALED_KEYWORD) + } + + private fun KtParameter.isUsedInClassInitializer(containingClass: KtClass): Boolean { + val classInitializer = containingClass.body?.declarations?.firstIsInstanceOrNull() ?: return false + return hasUsages(classInitializer) + } } \ No newline at end of file diff --git a/idea/testData/inspections/canBePrimaryConstructorProperty/inspectionData/expected.xml b/idea/testData/inspections/canBePrimaryConstructorProperty/inspectionData/expected.xml index 5008e7dac64..a1d813478ef 100644 --- a/idea/testData/inspections/canBePrimaryConstructorProperty/inspectionData/expected.xml +++ b/idea/testData/inspections/canBePrimaryConstructorProperty/inspectionData/expected.xml @@ -15,4 +15,28 @@ Property is explicitly assigned to constructor parameter Property is explicitly assigned to parameter withType, can be declared directly in constructor + + properties.kt + 79 + light_idea_test_case + + Property is explicitly assigned to constructor parameter + Property is explicitly assigned to parameter property, can be declared directly in constructor + + + properties.kt + 87 + light_idea_test_case + + Property is explicitly assigned to constructor parameter + Property is explicitly assigned to parameter property, can be declared directly in constructor + + + properties.kt + 91 + light_idea_test_case + + Property is explicitly assigned to constructor parameter + Property is explicitly assigned to parameter property, can be declared directly in constructor + \ No newline at end of file diff --git a/idea/testData/inspections/canBePrimaryConstructorProperty/properties.kt b/idea/testData/inspections/canBePrimaryConstructorProperty/properties.kt index 139b0782f61..6a4f0df95b8 100644 --- a/idea/testData/inspections/canBePrimaryConstructorProperty/properties.kt +++ b/idea/testData/inspections/canBePrimaryConstructorProperty/properties.kt @@ -44,4 +44,49 @@ class Bar(x : String) { override val x = x // Property is assigned to parameter, can be declared in ctor } } -} \ No newline at end of file +} + +// KT-32561 +open class X(property: String) { + init { + print(property) + } + + open val property: String = property +} + +abstract class X2(property: String) { + init { + print(property) + } + + open val property: String = property +} + +sealed class X3(property: String) { + init { + print(property) + } + + open val property: String = property +} + +open class X4(property: String) { + init { + print(property) + } + + val property: String = property +} + +class X5(property: String) { + init { + print(property) + } + + open val property: String = property +} + +open class X6(property: String) { + open val property: String = property +}