"Convert to primary constructor" inspection: do not report when property has setter
#KT-22142 Fixed
This commit is contained in:
committed by
Yan Zhulanow
parent
08f31758b8
commit
64f6ed586b
+34
-21
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.idea.intentions.ConvertSecondaryConstructorToPrimaryIntention.Companion.tryConvertToPropertyByParameterInitialization
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -25,7 +26,18 @@ import org.jetbrains.kotlin.util.kind
|
||||
|
||||
class ConvertSecondaryConstructorToPrimaryInspection : IntentionBasedInspection<KtSecondaryConstructor>(
|
||||
ConvertSecondaryConstructorToPrimaryIntention::class,
|
||||
{ constructor -> constructor.containingClass()?.secondaryConstructors?.size == 1 }
|
||||
fun(constructor: KtSecondaryConstructor): Boolean {
|
||||
val containingClass = constructor.containingClass() ?: return false
|
||||
if (containingClass.secondaryConstructors.size != 1) return false
|
||||
val context = containingClass.analyzeWithContent()
|
||||
val constructorDescriptor = context[BindingContext.CONSTRUCTOR, constructor] ?: return false
|
||||
for (statement in constructor.bodyExpression?.statements.orEmpty()) {
|
||||
val propertyDescriptor = statement.tryConvertToPropertyByParameterInitialization(constructorDescriptor, context)?.second
|
||||
val property = propertyDescriptor?.let { DescriptorToSourceUtils.descriptorToDeclaration(it) as? KtProperty }
|
||||
if (property?.setter?.hasBody() == true) return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
) {
|
||||
override fun inspectionTarget(element: KtSecondaryConstructor) = element.getConstructorKeyword()
|
||||
}
|
||||
@@ -62,26 +74,6 @@ class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingRangeIntentio
|
||||
return TextRange(element.startOffset, element.valueParameterList?.endOffset ?: element.getConstructorKeyword().endOffset)
|
||||
}
|
||||
|
||||
private fun KtExpression.tryConvertToPropertyByParameterInitialization(
|
||||
constructorDescriptor: ConstructorDescriptor, context: BindingContext
|
||||
): Pair<ValueParameterDescriptor, PropertyDescriptor>? {
|
||||
if (this !is KtBinaryExpression || operationToken != KtTokens.EQ) return null
|
||||
val rightReference = right as? KtReferenceExpression ?: return null
|
||||
val rightDescriptor = context[BindingContext.REFERENCE_TARGET, rightReference] as? ValueParameterDescriptor ?: return null
|
||||
if (rightDescriptor.containingDeclaration != constructorDescriptor) return null
|
||||
val leftReference = when (val left = left) {
|
||||
is KtReferenceExpression ->
|
||||
left
|
||||
is KtDotQualifiedExpression ->
|
||||
if (left.receiverExpression is KtThisExpression) left.selectorExpression as? KtReferenceExpression else null
|
||||
else ->
|
||||
null
|
||||
}
|
||||
|
||||
val leftDescriptor = context[BindingContext.REFERENCE_TARGET, leftReference] as? PropertyDescriptor ?: return null
|
||||
return rightDescriptor to leftDescriptor
|
||||
}
|
||||
|
||||
private fun KtSecondaryConstructor.extractInitializer(
|
||||
parameterToPropertyMap: MutableMap<ValueParameterDescriptor, PropertyDescriptor>,
|
||||
context: BindingContext,
|
||||
@@ -189,4 +181,25 @@ class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingRangeIntentio
|
||||
element.delete()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun KtExpression.tryConvertToPropertyByParameterInitialization(
|
||||
constructorDescriptor: ConstructorDescriptor, context: BindingContext
|
||||
): Pair<ValueParameterDescriptor, PropertyDescriptor>? {
|
||||
if (this !is KtBinaryExpression || operationToken != KtTokens.EQ) return null
|
||||
val rightReference = right as? KtReferenceExpression ?: return null
|
||||
val rightDescriptor = context[BindingContext.REFERENCE_TARGET, rightReference] as? ValueParameterDescriptor ?: return null
|
||||
if (rightDescriptor.containingDeclaration != constructorDescriptor) return null
|
||||
val leftReference = when (val left = left) {
|
||||
is KtReferenceExpression ->
|
||||
left
|
||||
is KtDotQualifiedExpression ->
|
||||
if (left.receiverExpression is KtThisExpression) left.selectorExpression as? KtReferenceExpression else null
|
||||
else ->
|
||||
null
|
||||
}
|
||||
val leftDescriptor = context[BindingContext.REFERENCE_TARGET, leftReference] as? PropertyDescriptor ?: return null
|
||||
return rightDescriptor to leftDescriptor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,17 @@ class NotSingle {
|
||||
constructor(x: Int) {
|
||||
this.x = x
|
||||
}
|
||||
}
|
||||
|
||||
// KT-22142
|
||||
class Person {
|
||||
constructor(email: String) {
|
||||
this.email = email
|
||||
}
|
||||
|
||||
var email: String
|
||||
set(value) {
|
||||
require(value.isNotBlank(), { "The email cannot be blank" })
|
||||
field = value
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user