Code improvements in IfThenToElvisIntention
This commit is contained in:
@@ -246,8 +246,6 @@ if.then.to.double.bang.replace.exception=Replace 'if' expression with '!!' expre
|
||||
if.then.to.double.bang.family=Replace 'if' Expression with '!!' Expression
|
||||
elvis.to.if.then=Replace elvis expression with 'if' expression
|
||||
elvis.to.if.then.family=Replace Elvis Expression with 'if' Expression
|
||||
if.then.to.elvis=Replace 'if' expression with elvis expression
|
||||
if.then.to.elvis.family=Replace 'if' Expression with Elvis Expression
|
||||
safe.access.to.if.then=Replace safe access expression with 'if' expression
|
||||
safe.access.to.if.then.family=Replace Safe Access Expression with 'if' Expression
|
||||
if.then.to.safe.access=Replace 'if' expression with safe access expression
|
||||
|
||||
@@ -22,6 +22,8 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiRecursiveElementVisitor
|
||||
import org.jetbrains.kotlin.JetNodeTypes
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.expressionComparedToNull
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
|
||||
import org.jetbrains.kotlin.idea.util.isNothing
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -84,14 +86,13 @@ public class IfNullToElvisIntention : JetSelfTargetingOffsetIndependentIntention
|
||||
|
||||
val binaryExpression = ifExpression.getCondition() as? JetBinaryExpression ?: return null
|
||||
if (binaryExpression.getOperationToken() != JetTokens.EQEQ) return null
|
||||
if (binaryExpression.getRight()?.getNode()?.getElementType() != JetNodeTypes.NULL) return null
|
||||
val left = binaryExpression.getLeft() as? JetSimpleNameExpression ?: return null
|
||||
val value = binaryExpression.expressionComparedToNull() as? JetSimpleNameExpression ?: return null
|
||||
|
||||
if (ifExpression.getParent() !is JetBlockExpression) return null
|
||||
val prevStatement = ifExpression.siblings(forward = false, withItself = false)
|
||||
.firstIsInstanceOrNull<JetExpression>() ?: return null
|
||||
if (prevStatement !is JetVariableDeclaration) return null
|
||||
if (prevStatement.getNameAsName() != left.getReferencedNameAsName()) return null
|
||||
if (prevStatement.getNameAsName() != value.getReferencedNameAsName()) return null
|
||||
val initializer = prevStatement.getInitializer() ?: return null
|
||||
val then = ifExpression.getThen() ?: return null
|
||||
|
||||
|
||||
+23
-30
@@ -16,34 +16,37 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.intentions.branchedTransformations
|
||||
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineValHandler
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import com.intellij.psi.search.LocalSearchScope
|
||||
import com.intellij.psi.search.searches.ReferencesSearch
|
||||
import org.jetbrains.kotlin.JetNodeTypes
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.refactoring.inline.KotlinInlineValHandler
|
||||
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
|
||||
val NULL_PTR_EXCEPTION_FQ = "java.lang.NullPointerException"
|
||||
val KOTLIN_NULL_PTR_EXCEPTION_FQ = "kotlin.KotlinNullPointerException"
|
||||
|
||||
fun JetBinaryExpression.comparesNonNullToNull(): Boolean {
|
||||
fun JetBinaryExpression.expressionComparedToNull(): JetExpression? {
|
||||
val operationToken = this.getOperationToken()
|
||||
val rhs = this.getRight()
|
||||
val lhs = this.getLeft()
|
||||
if (rhs == null || lhs == null) return false
|
||||
if (operationToken != JetTokens.EQEQ && operationToken != JetTokens.EXCLEQ) return null
|
||||
|
||||
val rightIsNull = rhs.isNullExpression()
|
||||
val leftIsNull = lhs.isNullExpression()
|
||||
return leftIsNull != rightIsNull && (operationToken == JetTokens.EQEQ || operationToken == JetTokens.EXCLEQ)
|
||||
val right = this.getRight() ?: return null
|
||||
val left = this.getLeft() ?: return null
|
||||
|
||||
val rightIsNull = right.isNullExpression()
|
||||
val leftIsNull = left.isNullExpression()
|
||||
if (leftIsNull == rightIsNull) return null
|
||||
return if (leftIsNull) right else left
|
||||
}
|
||||
|
||||
fun JetExpression.unwrapBlock(): JetExpression {
|
||||
@@ -57,18 +60,9 @@ fun JetExpression.unwrapBlock(): JetExpression {
|
||||
|
||||
fun JetExpression.isStatement(): Boolean = isUsedAsStatement(this.analyze())
|
||||
|
||||
fun JetBinaryExpression.getNonNullExpression(): JetExpression? = when {
|
||||
this.getLeft()?.isNullExpression() == false ->
|
||||
this.getLeft()
|
||||
this.getRight()?.isNullExpression() == false ->
|
||||
this.getRight()
|
||||
else ->
|
||||
null
|
||||
}
|
||||
fun JetExpression?.isNullExpression(): Boolean = this?.unwrapBlock()?.getNode()?.getElementType() == JetNodeTypes.NULL
|
||||
|
||||
fun JetExpression.isNullExpression(): Boolean = this.unwrapBlock().getText() == "null"
|
||||
|
||||
fun JetExpression.isNullExpressionOrEmptyBlock(): Boolean = this.isNullExpression() || this is JetBlockExpression && this.getStatements().isEmpty()
|
||||
fun JetExpression?.isNullExpressionOrEmptyBlock(): Boolean = this.isNullExpression() || this is JetBlockExpression && this.getStatements().isEmpty()
|
||||
|
||||
fun JetThrowExpression.throwsNullPointerExceptionWithNoArguments(): Boolean {
|
||||
val thrownExpression = this.getThrownExpression()
|
||||
@@ -76,8 +70,7 @@ fun JetThrowExpression.throwsNullPointerExceptionWithNoArguments(): Boolean {
|
||||
|
||||
val context = this.analyze()
|
||||
val descriptor = context.get(BindingContext.REFERENCE_TARGET, thrownExpression.getCalleeExpression() as JetSimpleNameExpression)
|
||||
val declDescriptor = descriptor?.getContainingDeclaration()
|
||||
if (declDescriptor == null) return false
|
||||
val declDescriptor = descriptor?.getContainingDeclaration() ?: return false
|
||||
|
||||
val exceptionName = DescriptorUtils.getFqName(declDescriptor).asString()
|
||||
return (exceptionName == NULL_PTR_EXCEPTION_FQ || exceptionName == KOTLIN_NULL_PTR_EXCEPTION_FQ) && thrownExpression.getValueArguments().isEmpty()
|
||||
|
||||
+3
-8
@@ -29,18 +29,13 @@ import org.jetbrains.kotlin.psi.JetThrowExpression
|
||||
public class IfThenToDoubleBangIntention : JetSelfTargetingOffsetIndependentIntention<JetIfExpression>("if.then.to.double.bang", javaClass()) {
|
||||
|
||||
override fun isApplicableTo(element: JetIfExpression): Boolean {
|
||||
val condition = element.getCondition()
|
||||
val condition = element.getCondition() as? JetBinaryExpression ?: return false
|
||||
val thenClause = element.getThen()
|
||||
val elseClause = element.getElse()
|
||||
|
||||
if (condition !is JetBinaryExpression || !condition.comparesNonNullToNull()) return false
|
||||
|
||||
val expression = condition.getNonNullExpression()
|
||||
|
||||
if (expression == null) return false
|
||||
val expression = condition.expressionComparedToNull() ?: return false
|
||||
|
||||
val token = condition.getOperationToken()
|
||||
if (token != JetTokens.EQEQ && token != JetTokens.EXCLEQ) return false
|
||||
|
||||
val throwExpression =
|
||||
when (token) {
|
||||
@@ -80,7 +75,7 @@ public class IfThenToDoubleBangIntention : JetSelfTargetingOffsetIndependentInte
|
||||
override fun applyTo(element: JetIfExpression, editor: Editor) {
|
||||
val condition = element.getCondition() as JetBinaryExpression
|
||||
|
||||
val expression = checkNotNull(condition.getNonNullExpression(), "condition must contain non null expression")
|
||||
val expression = condition.expressionComparedToNull()!!
|
||||
val resultingExprString = expression.getText() + "!!"
|
||||
val result = element.replace(resultingExprString) as JetPostfixExpression
|
||||
|
||||
|
||||
+14
-19
@@ -17,21 +17,22 @@
|
||||
package org.jetbrains.kotlin.idea.intentions.branchedTransformations.intentions
|
||||
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.kotlin.JetNodeTypes
|
||||
import org.jetbrains.kotlin.idea.intentions.JetSelfTargetingOffsetIndependentIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.*
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.replaced
|
||||
|
||||
public class IfThenToElvisIntention : JetSelfTargetingOffsetIndependentIntention<JetIfExpression>("if.then.to.elvis", javaClass()) {
|
||||
public class IfThenToElvisIntention : JetSelfTargetingOffsetIndependentIntention<JetIfExpression>(javaClass(), "Replace 'if' expression with elvis expression") {
|
||||
|
||||
override fun isApplicableTo(element: JetIfExpression): Boolean {
|
||||
val condition = element.getCondition()
|
||||
val thenClause = element.getThen()
|
||||
val elseClause = element.getElse()
|
||||
if (thenClause == null || elseClause == null || condition !is JetBinaryExpression || !condition.comparesNonNullToNull()) return false
|
||||
val condition = element.getCondition() as? JetBinaryExpression ?: return false
|
||||
val thenClause = element.getThen() ?: return false
|
||||
val elseClause = element.getElse() ?: return false
|
||||
|
||||
val expression = condition.getNonNullExpression()
|
||||
if (expression == null || !expression.isStableVariable()) return false
|
||||
val expression = condition.expressionComparedToNull() ?: return false
|
||||
if (!expression.isStableVariable()) return false
|
||||
|
||||
return when (condition.getOperationToken()) {
|
||||
JetTokens.EQEQ ->
|
||||
@@ -49,7 +50,7 @@ public class IfThenToElvisIntention : JetSelfTargetingOffsetIndependentIntention
|
||||
|
||||
private fun JetExpression.isNotNullExpression(): Boolean {
|
||||
val innerExpression = this.unwrapBlock()
|
||||
return innerExpression !is JetBlockExpression && innerExpression.getText() != "null"
|
||||
return innerExpression !is JetBlockExpression && innerExpression.getNode().getElementType() != JetNodeTypes.NULL
|
||||
}
|
||||
|
||||
override fun applyTo(element: JetIfExpression, editor: Editor) {
|
||||
@@ -60,8 +61,8 @@ public class IfThenToElvisIntention : JetSelfTargetingOffsetIndependentIntention
|
||||
public fun applyTo(element: JetIfExpression): JetBinaryExpression {
|
||||
val condition = element.getCondition() as JetBinaryExpression
|
||||
|
||||
val thenClause = checkNotNull(element.getThen(), "The then clause cannot be null")
|
||||
val elseClause = checkNotNull(element.getElse(), "The else clause cannot be null")
|
||||
val thenClause = element.getThen()!!
|
||||
val elseClause = element.getElse()!!
|
||||
val thenExpression = thenClause.unwrapBlock()
|
||||
val elseExpression = elseClause.unwrapBlock()
|
||||
|
||||
@@ -69,16 +70,10 @@ public class IfThenToElvisIntention : JetSelfTargetingOffsetIndependentIntention
|
||||
when(condition.getOperationToken()) {
|
||||
JetTokens.EQEQ -> Pair(elseExpression, thenExpression)
|
||||
JetTokens.EXCLEQ -> Pair(thenExpression, elseExpression)
|
||||
else -> throw IllegalStateException("Operation token must be either null or not null")
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
val resultingExprString = "${left.getText()} ?: ${right.getText()}"
|
||||
val resultingExpression = JetPsiUtil.deparenthesize(element.replace(resultingExprString) as? JetExpression)
|
||||
|
||||
assert(resultingExpression is JetBinaryExpression) {
|
||||
"Unexpected expression type: ${resultingExpression?.javaClass}, expected JetBinaryExpression, element = '${element.getText()}'"
|
||||
}
|
||||
|
||||
return resultingExpression as JetBinaryExpression
|
||||
val newExpr = element.replaced(JetPsiFactory(element).createExpressionByPattern("$0 ?: $1", left, right))
|
||||
return JetPsiUtil.deparenthesize(newExpr) as JetBinaryExpression
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -25,13 +25,12 @@ import org.jetbrains.kotlin.psi.*
|
||||
public class IfThenToSafeAccessIntention : JetSelfTargetingOffsetIndependentIntention<JetIfExpression>("if.then.to.safe.access", javaClass()) {
|
||||
|
||||
override fun isApplicableTo(element: JetIfExpression): Boolean {
|
||||
val condition = element.getCondition()
|
||||
val condition = element.getCondition() as? JetBinaryExpression ?: return false
|
||||
val thenClause = element.getThen()
|
||||
val elseClause = element.getElse()
|
||||
if (condition !is JetBinaryExpression || !condition.comparesNonNullToNull()) return false
|
||||
|
||||
val receiverExpression = condition.getNonNullExpression()
|
||||
if (receiverExpression == null || !receiverExpression.isStableVariable()) return false
|
||||
val receiverExpression = condition.expressionComparedToNull() ?: return false
|
||||
if (!receiverExpression.isStableVariable()) return false
|
||||
|
||||
return when (condition.getOperationToken()) {
|
||||
JetTokens.EQEQ ->
|
||||
@@ -54,7 +53,7 @@ public class IfThenToSafeAccessIntention : JetSelfTargetingOffsetIndependentInte
|
||||
|
||||
public fun applyTo(element: JetIfExpression): JetSafeQualifiedExpression {
|
||||
val condition = element.getCondition() as JetBinaryExpression
|
||||
val receiverExpression = checkNotNull(condition.getNonNullExpression(), "The receiver expression cannot be null")
|
||||
val receiverExpression = condition.expressionComparedToNull()!!
|
||||
|
||||
val selectorExpression =
|
||||
when(condition.getOperationToken()) {
|
||||
|
||||
Reference in New Issue
Block a user