Introduce subject to when: don't perform analysis in if transformation

Otherwise we get an exception about non-analysable file
Related to KT-18772
This commit is contained in:
Mikhail Glukhikh
2019-09-27 09:04:17 +03:00
parent fdf9acfb6a
commit d45e83b27d
2 changed files with 15 additions and 11 deletions
@@ -37,7 +37,7 @@ fun KtWhenCondition.toExpression(subject: KtExpression?): KtExpression {
} }
} }
fun KtWhenExpression.getSubjectToIntroduce(): KtExpression? { fun KtWhenExpression.getSubjectToIntroduce(checkConstants: Boolean = true): KtExpression? {
if (subjectExpression != null) return null if (subjectExpression != null) return null
var lastCandidate: KtExpression? = null var lastCandidate: KtExpression? = null
@@ -48,7 +48,7 @@ fun KtWhenExpression.getSubjectToIntroduce(): KtExpression? {
for (condition in conditions) { for (condition in conditions) {
if (condition !is KtWhenConditionWithExpression) return null if (condition !is KtWhenConditionWithExpression) return null
val candidate = condition.expression?.getWhenConditionSubjectCandidate() ?: return null val candidate = condition.expression?.getWhenConditionSubjectCandidate(checkConstants) ?: return null
if (candidate !is KtNameReferenceExpression if (candidate !is KtNameReferenceExpression
&& (candidate as? KtQualifiedExpression)?.selectorExpression !is KtNameReferenceExpression && (candidate as? KtQualifiedExpression)?.selectorExpression !is KtNameReferenceExpression
&& candidate !is KtThisExpression && candidate !is KtThisExpression
@@ -65,7 +65,7 @@ fun KtWhenExpression.getSubjectToIntroduce(): KtExpression? {
return lastCandidate return lastCandidate
} }
private fun KtExpression?.getWhenConditionSubjectCandidate(): KtExpression? = when (this) { private fun KtExpression?.getWhenConditionSubjectCandidate(checkConstants: Boolean): KtExpression? = when (this) {
is KtIsExpression -> leftHandSide is KtIsExpression -> leftHandSide
is KtBinaryExpression -> { is KtBinaryExpression -> {
@@ -74,10 +74,11 @@ private fun KtExpression?.getWhenConditionSubjectCandidate(): KtExpression? = wh
when (operationToken) { when (operationToken) {
KtTokens.IN_KEYWORD, KtTokens.NOT_IN -> lhs KtTokens.IN_KEYWORD, KtTokens.NOT_IN -> lhs
KtTokens.EQEQ -> KtTokens.EQEQ ->
lhs?.takeIf { it.hasCandidateNameReferenceExpression() } ?: rhs?.takeIf { it.hasCandidateNameReferenceExpression() } lhs?.takeIf { it.hasCandidateNameReferenceExpression(checkConstants) }
?: rhs?.takeIf { it.hasCandidateNameReferenceExpression(checkConstants) }
KtTokens.OROR -> { KtTokens.OROR -> {
val leftCandidate = lhs.getWhenConditionSubjectCandidate() val leftCandidate = lhs.getWhenConditionSubjectCandidate(checkConstants)
val rightCandidate = rhs.getWhenConditionSubjectCandidate() val rightCandidate = rhs.getWhenConditionSubjectCandidate(checkConstants)
if (leftCandidate.matches(rightCandidate)) leftCandidate else null if (leftCandidate.matches(rightCandidate)) leftCandidate else null
} }
else -> null else -> null
@@ -88,17 +89,20 @@ private fun KtExpression?.getWhenConditionSubjectCandidate(): KtExpression? = wh
else -> null else -> null
} }
private fun KtExpression.hasCandidateNameReferenceExpression(): Boolean { private fun KtExpression.hasCandidateNameReferenceExpression(checkConstants: Boolean): Boolean {
val nameReferenceExpression = this as? KtNameReferenceExpression val nameReferenceExpression = this as? KtNameReferenceExpression
?: (this as? KtQualifiedExpression)?.selectorExpression as? KtNameReferenceExpression ?: (this as? KtQualifiedExpression)?.selectorExpression as? KtNameReferenceExpression
?: return false ?: return false
if (!checkConstants) {
return true
}
val resolved = nameReferenceExpression.mainReference.resolve() val resolved = nameReferenceExpression.mainReference.resolve()
if (resolved is KtObjectDeclaration || (resolved as? KtProperty)?.hasModifier(KtTokens.CONST_KEYWORD) == true) return false if (resolved is KtObjectDeclaration || (resolved as? KtProperty)?.hasModifier(KtTokens.CONST_KEYWORD) == true) return false
return true return true
} }
fun KtWhenExpression.introduceSubject(): KtWhenExpression? { fun KtWhenExpression.introduceSubject(checkConstants: Boolean = true): KtWhenExpression? {
val subject = getSubjectToIntroduce() ?: return null val subject = getSubjectToIntroduce(checkConstants) ?: return null
val commentSaver = CommentSaver(this, saveLineBreaks = true) val commentSaver = CommentSaver(this, saveLineBreaks = true)
@@ -191,8 +191,8 @@ class IfToWhenIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpres
} as KtWhenExpression } as KtWhenExpression
if (whenExpression.getSubjectToIntroduce() != null) { if (whenExpression.getSubjectToIntroduce(checkConstants = false) != null) {
whenExpression = whenExpression.introduceSubject() ?: return whenExpression = whenExpression.introduceSubject(checkConstants = false) ?: return
} }
val result = ifExpression.replaced(whenExpression) val result = ifExpression.replaced(whenExpression)