"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.KotlinBundle
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithContent
|
||||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
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.idea.util.CommentSaver
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
@@ -25,7 +26,18 @@ import org.jetbrains.kotlin.util.kind
|
|||||||
|
|
||||||
class ConvertSecondaryConstructorToPrimaryInspection : IntentionBasedInspection<KtSecondaryConstructor>(
|
class ConvertSecondaryConstructorToPrimaryInspection : IntentionBasedInspection<KtSecondaryConstructor>(
|
||||||
ConvertSecondaryConstructorToPrimaryIntention::class,
|
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()
|
override fun inspectionTarget(element: KtSecondaryConstructor) = element.getConstructorKeyword()
|
||||||
}
|
}
|
||||||
@@ -62,26 +74,6 @@ class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingRangeIntentio
|
|||||||
return TextRange(element.startOffset, element.valueParameterList?.endOffset ?: element.getConstructorKeyword().endOffset)
|
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(
|
private fun KtSecondaryConstructor.extractInitializer(
|
||||||
parameterToPropertyMap: MutableMap<ValueParameterDescriptor, PropertyDescriptor>,
|
parameterToPropertyMap: MutableMap<ValueParameterDescriptor, PropertyDescriptor>,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
@@ -189,4 +181,25 @@ class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingRangeIntentio
|
|||||||
element.delete()
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -17,3 +17,16 @@ class NotSingle {
|
|||||||
this.x = x
|
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