CanBePrimaryConstructorPropertyInspection: do not report for 'open' property used in class initializer in 'open' class

This commit is contained in:
Toshiaki Kameyama
2020-02-04 13:46:28 +09:00
committed by Dmitry Gridin
parent 963258189a
commit 0b9106b0f8
3 changed files with 91 additions and 7 deletions
@@ -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<KtClassInitializer>() ?: return false
return hasUsages(classInitializer)
}
}
@@ -15,4 +15,28 @@
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Property is explicitly assigned to constructor parameter</problem_class>
<description>Property is explicitly assigned to parameter withType, can be declared directly in constructor</description>
</problem>
<problem>
<file>properties.kt</file>
<line>79</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/properties.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Property is explicitly assigned to constructor parameter</problem_class>
<description>Property is explicitly assigned to parameter property, can be declared directly in constructor</description>
</problem>
<problem>
<file>properties.kt</file>
<line>87</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/properties.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Property is explicitly assigned to constructor parameter</problem_class>
<description>Property is explicitly assigned to parameter property, can be declared directly in constructor</description>
</problem>
<problem>
<file>properties.kt</file>
<line>91</line>
<module>light_idea_test_case</module>
<entry_point TYPE="file" FQNAME="temp:///src/properties.kt" />
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Property is explicitly assigned to constructor parameter</problem_class>
<description>Property is explicitly assigned to parameter property, can be declared directly in constructor</description>
</problem>
</problems>
@@ -44,4 +44,49 @@ class Bar(x : String) {
override val x = x // Property is assigned to parameter, can be declared in ctor
}
}
}
}
// 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
}