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